Jump to content
  • Advertisement

packetpirate

Member
  • Content Count

    23
  • Joined

  • Last visited

Community Reputation

106 Neutral

About packetpirate

  • Rank
    Member

Personal Information

Social

  • Twitter
    packetpirate
  • Github
    https://github.com/packetpirate
  1. Figured it out, and I feel so indescribably stupid right now. So the problem tiles were tiles that had the horizontal and diagonal flip bits set, right? Well I set a conditional breakpoint for the TTile constructor for any tiles where the horizontal boolean got set, and guess what? Not a single tile. Then I noticed something..... the horizontal bit is at 0x80000000, which is 2,147,483,648. The problem with that being... I was storing my hex constants in integers... So the 0x80000000 constant would probably have overflown and it would have been comparing a completely different value with the TID. Anyways, it works now. I also changed the drawing method to avoid all the confusing flipping nonsense and just hardcoded a rotation value for each flip condition.
  2. Hmm... I think the reason the flips aren't working as expected are because it's not actually flipping the pixel data... it's just changing the offset and width of the image object. Might get muddled when also dealing with rotations.
  3. That's a method of the Graphics class, which is part of Slick. https://github.com/ariejan/slick2d/blob/master/src/org/newdawn/slick/Graphics.java
  4. I made some more changes to the rotation method used by constructMap() so that it now looks like this: public void constructMap() { try { Image tileset = AssetManager.getManager().getImage("grave_wave_tiles"); context = map.getGraphics(); context.setBackground(Color.black); context.clear(); for(int i = 0; i < layers.size(); i++) { TLayer layer = layers.get(i); for(int y = 0; y < mapHeight; y++) { for(int x = 0; x < mapWidth; x++) { TTile tile = layer.getTile(x, y); Image img = tile.getImage(tileset, tileWidth, tileHeight); if(img != null) { if(tile.isFlipped(TTile.FLIP_DIAGONAL)) { // If we should flip this diagonally, first rotate by 90 degrees. boolean fh = tile.isFlipped(TTile.FLIP_HORIZONTAL); boolean fv = tile.isFlipped(TTile.FLIP_VERTICAL); int angle = 270; // Default to CCW for vertically flipped tiles. if(fh) angle = 90; // Clockwise (CW) for horizontally flipped tiles. context.rotate(((x * tileWidth) + (tileWidth / 2)), ((y * tileHeight) + (tileHeight / 2)), angle); // Then flip the image horizontally... Image flipped = img.getFlippedCopy(!fh, !fv); context.drawImage(flipped, (x * tileWidth), (y * tileHeight)); // Reset the rotation of the canvas. context.resetTransform(); } else { context.drawImage(img, (x * tileWidth), (y * tileHeight)); } } } } } context.flush(); } catch(SlickException se) { System.err.println("ERROR: Could not construct map!"); se.printStackTrace(); } } And this DOES show the correct rotation, but only for the tiles where the "flip horizontal" bit is set. The basic formula is: (Horizontal, Diagonal) = Horizontal Flip + CW Rotation + Vertical Flip (Vertical, Diagonal) = Vertical Flip + CCW Rotation + Horizontal Flip The "flip vertical" tiles seem to be at weird angles. I did the rotations out in Aseprite just to show that they were the correct rotations and flips to use to get the desired effect, and Aseprite shows the correct end result, so I'm not sure why I don't get what I want in the game... I've attached a couple screenshots showing where rotations went right, and where they went wrong. The tiles that went wrong are the ones where the vertical flip bit was set. Any ideas?
  5. Here is the TMap class, which is the container for all the map data. https://github.com/packetpirate/Generic-Zombie-Shooter-Redux/blob/master/src/com/gzsr/tmx/TMap.java And here is the TTile class, which parses the tile IDs and gives the TMap class the image to render to the map graphics context. https://github.com/packetpirate/Generic-Zombie-Shooter-Redux/blob/master/src/com/gzsr/tmx/TTile.java There are only two other classes relevant to dealing with the TMX data, but they aren't relevant. I should say that the second method of rotating the canvas, where I rotate the graphics context directly, DOES work, but only for some tiles. It seems like depending on whether it's a horizontal or vertical flip, it either works, or doesn't.
  6. The code in my original post is called in the constructMap() method of my map object. It uses the ID of the tile from Tiled to calculate the offsets of the image in the tileset, then gets a subimage from the tileset containing just that tile. Then, it's SUPPOSED to rotate it if the flip diagonal bit is set, which as I've already said, it doesn't. If you're curious to see the constructMap() method that calls the above method, this is it: public void constructMap() { try { Image tileset = AssetManager.getManager().getImage("grave_wave_tiles"); context = map.getGraphics(); context.setBackground(Color.black); context.clear(); for(int i = 0; i < layers.size(); i++) { TLayer layer = layers.get(i); for(int y = 0; y < mapHeight; y++) { for(int x = 0; x < mapWidth; x++) { TTile tile = layer.getTile(x, y); Image img = tile.getImage(tileset, tileWidth, tileHeight); if(img != null) context.drawImage(img, (x * tileWidth), (y * tileHeight)); } } } context.flush(); } catch(SlickException se) { System.err.println("ERROR: Could not construct map!"); se.printStackTrace(); } } In the above code, context is a Graphics object and map is an Image (the image everything is rendered to). This method is called after the data is loaded from the TMX file. An Image object is used as a buffer to draw the tiles to it so I only have to do it once. That way, in the future, I can just render the image. What I meant when I mentioned rotating the graphical context is that I had attempted another method of rotating the tiles where I did something like this instead in the constructMap() method: public void constructMap() { try { Image tileset = AssetManager.getManager().getImage("grave_wave_tiles"); context = map.getGraphics(); context.setBackground(Color.black); context.clear(); for(int i = 0; i < layers.size(); i++) { TLayer layer = layers.get(i); for(int y = 0; y < mapHeight; y++) { for(int x = 0; x < mapWidth; x++) { TTile tile = layer.getTile(x, y); Image img = tile.getImage(tileset, tileWidth, tileHeight); if(img != null) { if(tile.isFlipped(TTile.FLIP_DIAGONAL)) { // If we should flip this diagonally, first rotate by 90 degrees. context.rotate(((x * tileWidth) + (tileWidth / 2)), ((y * tileHeight) + (tileHeight / 2)), 90); // Then flip the image horizontally... Image flipped = img.getFlippedCopy(true, false); context.drawImage(flipped, (x * tileWidth), (x * tileHeight)); // Reset the rotation of the canvas. context.rotate(((x * tileWidth) + (tileWidth / 2)), ((y * tileHeight) + (tileHeight / 2)), -90); } else { context.drawImage(img, (x * tileWidth), (y * tileHeight)); } } } } } context.flush(); } catch(SlickException se) { System.err.println("ERROR: Could not construct map!"); se.printStackTrace(); } } The problem with this code is, as I said, that it rotates the canvas, so the (x, y) coordinates for the tile are no longer the right position, and when it rotates back, now the tile I just drew is in a completely different place than it should be. I have a feeling what I want could be achieved by transforming the (x, y) position of the tile once the canvas is rotated, but I don't know exactly what to do with the coordinates to get what I want. Does that clear anything up? If not, I can just link you to the relevant classes on Github so you can take a better look.
  7. I just finished writing a parser for TMX data (Tiled maps), and the way Tiled handles rotated tiles is by using three bit flags for flipping an image horizontally, vertically, and diagonally, to allow for rotation. Unless I'm wrong, flipping an image "diagonally" is just rotating 90 degrees CCW (counter-clockwise) and then flipping horizontally. So I tried to implement this when I create the sub-image of the tileset for each tile: public Image getImage(Image tileset, int w, int h) { if(tid == 0) return null; int nh = tileset.getWidth() / w; // Number of tiles in this tileset horizontally. // Offsets to be multiplied by tile width and height to get origin point of tile. int ox = ((tid - 1) % nh); // Subtract 1 because the TID numbers are 1-indexed (why use 0 to indicate nothing? why not -1? stupid Tiled...) int oy = ((tid - 1) / nh); Image sub = tileset.getSubImage((ox * w), (oy * h), w, h); // If any of the flip bits are set, flip the image. if(fh || fv) sub = sub.getFlippedCopy(fh, fv); if(fd) { // To flip diagonally, rotate counter-clockwise, then flip it horizontally. sub.setRotation(-90); sub = sub.getFlippedCopy(true, false); } return sub; } Specifically, the area where I set the rotation of the sub-image is what's causing my problem. Despite setting the rotation, the image is not rotated on the canvas. Doing a little digging into the library (what little information there is), it seems that the Image class' internal rotate methods don't actually do anything to the image, and most rotation is done using the Graphics context's rotate methods, which rotate the entire context and then draw the image. The only problem with that is that if I rotate my graphics context, which is the map I'm constructing using these tiles, then the coordinates I give to draw the tile are no longer correct because of the rotated context, so my tiles come out all over the place. What would be my solution here for rotating the images? Is there a transformation I can do to the coordinates once the graphics context is rotated so they draw in the correct position? I don't know anything about linear algebra, so I'm not sure what to do from here.
  8. packetpirate

    How to design this game weapon?

    Well that works for now. I guess I can always change it in the future if I really want to make it better.
  9. packetpirate

    How to design this game weapon?

    This is where my lack of experience making game engines is a problem. I understand what you're saying; I'm just not sure how to incorporate it into the code I have now in an efficient way. Sure, I could set a flag on the enemy that they can't move; but how would I know when to release that flag? I thought about simply making a method that moves the enemy backward on their move path to effectively cancel out the previous movement, but is this really a good design for how it should work? At what point is adding methods to make every little feature work cumbersome and bad design? I know I can't expect anyone to look through my code base, as it's currently ~4,700 lines, but it would be nice to have someone who could help me with these problems in a more detailed manner. I already have status effects, although they are currently only applied to the player.
  10. I know how to get the pixel color of an image, but the problem is that both images are rotated, so I would need to transform the position passed to the image's relative coordinates to get the rotated coordinates, and I don't know the math behind that. Wouldn't that be slow, anyway? Are you suggesting I check each pixel of the particle to see if it overlaps with a pixel in the same relative position in the enemy image? I've never actually read any books on game architecture because unfortunately, good ones are few and far between now that there exist engines like Unity that make it unnecessary to create your own engine. So I've taught myself everything, and I realize this makes it difficult to create a "good" engine. Any suggestions?
  11. I'm currently remaking a game I made a few years back using Slick2D (as opposed to Swing/AWT, which was a terrible idea). I've fleshed out a lot of the background architecture, but I'm starting to run into issues with my architecture and I'm not sure how to proceed. The game I'm making is an overhead shooter. It's wave-based, with hordes of zombies coming at you. There are 10 weapons to choose from. Specifically, my latest issue is with a particular "weapon" I'm designing; the Laser Barrier. In the previous game, I had a "Laser Wire" weapon, which when two terminals were placed on the ground, created a wire made of laser on the ground that would damage enemies that passed through. Problem was that it didn't do enough damage in the short time that the enemies would be colliding with it for it to be of any use, so it was a waste of money. In the remake, I'm instead creating the "Laser Barrier", which visually looks the same, but instead of damaging enemies that touch it, it will act as an obstacle that enemies can't walk through. The enemies damage the shield while they are in contact with it until the laser barrier collapses. Projectiles however, can still pass through the barrier, allowing the player, and certain enemies, to shoot through them. The issue I'm running into, though, is the method of communicating between the Laser Wire itself and the enemy touching it. I'm currently able to detect a collision between the enemy and wire projected between the two laser terminals, but I'm not sure how I can implement the actual movement blocking part. It would take too much text to explain how it works, so here are the relevant files in my project: Player class - the checkProjectiles() method on line 344 is where the game loop checks for collisions between the player's weapon projectiles and the an enemy passed as an argument. On line 350, you can see that when there is a collision between the enemy and the LaserNode object (collision method is linked below), the laser node takes damage so that it will eventually be destroyed. I figured this is where the "movement blocking" should be, as I have access to the terminal and the enemy, and this is where a collision is confirmed. LaserNode class - this is the class representing the laser terminals on the ground that project the laser beam between them. The checkCollision() method on line 57 is used to determine if the enemy is touching either of the terminals, or if it is touching the beam itself. Enemy class - this is the base class for all game enemies. You can see what methods are available to all enemies, so perhaps this can provide some insight into what could be done to communicate with the LaserNode. I realize it's a lot to ask considering the scope of my project, but could someone give me an idea of how to communicate between the LaserNode and Enemy so that the enemy knows not to move when touching the LaserNode? The only methods I can think of seem cumbersome and it seems like I'd be adding a lot to the Enemy class just to get this one feature working. I'd love to script these weapons with LUA, but I never learned how to integrate a scripting language into my game architecture. I also have limited experience writing game engines, so I'm sure there's a lot of refinement that could be done to make my game architecture less restricting. I don't expect anyone to actually comb through my project and make suggestions, but I would super appreciate it.
  12. One issue with this I can think of... Slick does have a Line class that has an intersects method that can check for intersection with a shape, but I don't want the projectile to collide with the entire image... otherwise I could just do rectangle collision like I was doing before (which worked fine, but I would see projectiles disappear before hitting the actual body of the zombie, for example). This is why I switched to using a radius, which looks a little better. I would need a way to define a shape for each frame of the animation representing the zombie and check for collision with it, or get a reliably accurate enough shape to represent the body. But defining a shape would require a set of points, which would be needlessly complicated since I would need to manually find a set of points around the image to define the shape of the animation. There has to be a better way to approach the line collision. I thought about using a black and white "mask" of the image and simply seeing if any of the pixels along the raycast are in the mask's "white" area (which I wouldn't even know how to do in an efficient manner), but at some point this would be a lot of processing work for each projectile, and I'm really not sure what the best approach to this is.
  13. Well thank you for taking the time to look at the code. Now I just need to find a decent article explaining the collision that vinterberg describes.
  14. Wrong update method. I was referring to the overridden update method of the BasicGameState class, which is what my GameState class uses as its main update method. I then call the update methods of my various game objects from there. I have no control over this particular update method, so I have no control over what information the delta variable gives me.
  15. I have no control over the update and render methods. BasicGameState is a Slick2D class. My only option is to do it through the overridden method. Do you know of any good articles that could explain the particular type of collision you're referring to?
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!