13 Replies Latest reply: Nov 23, 2009 2:29 PM by 843853 RSS

    map coordinate to screen coordinate algorithm

    843853
      I am working on a simple 2d RPG, but I ran into a problem while working in NPCs.

      Currently the player is fixed at the center of a panel and the map scrolls below him. The panel the character and map are drawn on is only 1000 by 520 pixels and the map image can be any size (currently testing with a 3000x1565 BufferedImage)

      I tried drawing the NPC's sprite on to the BufferedImage, and quickly realized that wasn't going to work for any kind of smooth animation (you would have to redraw the BufferedImage off screen each time the NPCs AI thread told him to move, which means the BufferedImage may or may not be complete when the panel was repainted by the player's animation thread) . I need to determine weather NPCs are on the screen and then translate or transform their map coordinate to screen (or panel) coordinates.

      I did a search on the forum, but couldn't find a quick answer if someone could help me out I'd appreciate it.
        • 1. Re: map coordinate to screen coordinate algorithm
          843853
          Someone on an other forum told me to find the map coordinates of the top left corner of the screen, then find the map coordinates of the NPC(they said player, but that didn't seem to make sense) and subtract character's map coordinated from screen's map coordinated to get the screen coordinates for the character.

          I wrote this little method the parameters are screen's map x, the screen's map y, the screen's width, the screen's height, the player character's map x, and the player character's map y.
          public void findScreen(int sx, int sy, int sw, int sh, int px, int py)
          {
              //make sure the NPC is on the screen
              if ( (mapX < px - sw/2 || mapX > px + sw/2 ) || (mapY < py - sh/2 || mapY > py + sw/2))
              {
                  draw = true;
              }
              else 
              {
                  draw = false;
              }
          
              if (draw == true)
              {
                  x = sx - mapX;
                  y = sy - mapY;
              }
          }
          The method is part of the super class that both my PlayerCharacter and AICharacter classes extend even though its not used on the player because he is fixed at the enter of the screen. I call it from my custom panel class that draws the map and character sprites with this monstrous call:
          npcs.findScreen(
          (player.mapX + player.getAvatar().getWidth(this)/2) - getWidth()/2,
          (player.mapY + player.getAvatar().getHeight(this)/2) - getHeight()/2 ,
          player.mapX + getWidth()/2,
          player.mapY + getHeight()/2,
          player.mapX + player.getAvatar().getWidth(this)/2,
          player.mapY + player.getAvatar().getHeight(this)/2 );
          The condition for checking if the NPC is on screen may not be right, but anyway the translation from map coordinates to screen coordinates didn't work.   Perhaps only because it doesn't take into account the top left corner of the screen could be off the map.  
          
          Does this look like the right algorithm?  It never sounded like it would work to me but I could be wrong.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
          • 2. Re: map coordinate to screen coordinate algorithm
            796262
            lessThanNate wrote:
            I am working on a simple 2d RPG, but I ran into a problem while working in NPCs.

            Currently the player is fixed at the center of a panel and the map scrolls below him. The panel the character and map are drawn on is only 1000 by 520 pixels and the map image can be any size (currently testing with a 3000x1565 BufferedImage)

            I tried drawing the NPC's sprite on to the BufferedImage, and quickly realized that wasn't going to work for any kind of smooth animation (you would have to redraw the BufferedImage off screen each time the NPCs AI thread told him to move, which means the BufferedImage may or may not be complete when the panel was repainted by the player's animation thread) . I need to determine weather NPCs are on the screen and then translate or transform their map coordinate to screen (or panel) coordinates.

            I did a search on the forum, but couldn't find a quick answer if someone could help me out I'd appreciate it.
            I'm not even sure what you're asking. Why would you have to redraw the whole BufferedImage if only a little part of it has changed?
            • 3. Re: map coordinate to screen coordinate algorithm
              843853
              Imagin the map and screen are the same size then the map coordinates are equals the screen coordinates...

              If the screen is smaller as the map then you need to know some screenX, screenY which told you where the screen
              is on your map. screenX and screenY are set by your scroll code (or key up/down/left/right...)

              Now to get 1) the map coordinate from the screen coordinate (or 2) screen coordinate from the map coordinate)
              is easy...


              E.g..

              1)
                   int playerMapX = playerScreenX + screenX;int playerMapY = playerScreenY + screenY;
              
                  
              2) ...
              • 4. Re: map coordinate to screen coordinate algorithm
                843853
                kevinaworkman wrote:
                I'm not even sure what you're asking. Why would you have to redraw the whole BufferedImage if only a little part of it has changed?
                Well, first there could be many NPCs on the map all moving around. Regardless I already said the redrawing the whole BufferedImage thing didn't work. Drawing the NPCs to the map BufferedImage was a bad idea.
                lessThanNate wrote:
                I tried drawing the NPC's sprite on to the BufferedImage, and quickly realized that wasn't going to work for any kind of smooth animation...
                • 5. Re: map coordinate to screen coordinate algorithm
                  843853
                  montsie wrote:
                  Now to get 1) the map coordinate from the screen coordinate (or 2) screen coordinate from the map coordinate)
                  is easy...


                  E.g..

                  1)
                  int playerMapX = playerScreenX + screenX;int playerMapY = playerScreenY + screenY;
                  So,
                  x = sx - mapX;
                  y = sy - mapY;
                  would work, as long as the sx, sy (screen's map x, screen's mapY) is not negative? What I have is the opposite of what you have, I want to find the screen x,y for the character given the map x,y of the character and the map x,y of the screen.
                  • 6. Re: map coordinate to screen coordinate algorithm
                    843853
                    Or wait, is it:
                    x = mapX - sx;
                    y = mapY - sy;
                    Sorry, I am terrible with math.
                    • 7. Re: map coordinate to screen coordinate algorithm
                      796262
                      lessThanNate wrote:
                      kevinaworkman wrote:
                      I'm not even sure what you're asking. Why would you have to redraw the whole BufferedImage if only a little part of it has changed?
                      Well, first there could be many NPCs on the map all moving around. Regardless I already said the redrawing the whole BufferedImage thing didn't work. Drawing the NPCs to the map BufferedImage was a bad idea.
                      lessThanNate wrote:
                      I tried drawing the NPC's sprite on to the BufferedImage, and quickly realized that wasn't going to work for any kind of smooth animation...
                      Yeah, my point was that drawing the NPC sprites on the BufferedImage could work, if you don't draw the entire thing. Every time a NPC moves, you only care about redrawing two places: where the NPC previously was, and where the NPC currently is. Redrawing things that haven't changed is what's killing you.

                      You haven't provided any code, so all of this is theoretical. But let's say you have an instance of BufferedImage that you update somehow. I assume you have a method that draws the entire thing, eh? Instead of that, you'd want another method that simply draws onto an appropriate sub-piece of the BufferedImage. If you're familiar with Swing at all, it's the difference between repaint() and repaint(x, y, width, height).

                      This is true for scrolling, too. Are you redrawing the entire BufferedImage everytime you move it?
                      • 8. Re: map coordinate to screen coordinate algorithm
                        843853
                        kevinaworkman wrote:
                        Yeah, my point was that drawing the NPC sprites on the BufferedImage could work, if you don't draw the entire thing...
                        I see now.
                        kevinaworkman wrote:
                        You haven't provided any code, so all of this is theoretical.
                        But its still isn't a good idea for what I am working with. With the way I have my sprite animations working if you try to draw the npcs to the BufferedImage it tends to cut out sequences of the animation. If I make another method for updating small pieces of the BufferedImage that may not happen I suppose.

                        Anyway thanks for the tip, It made me think of something else too, if I stick with not drawing NPCs to the buffered Image it would probably be a good idea not to run their animation threads if they are off screen.
                        • 9. Re: map coordinate to screen coordinate algorithm
                          843853
                          kevinaworkman wrote:
                          This is true for scrolling, too. Are you redrawing the entire BufferedImage everytime you move it?
                          Oh and no, I don't think I am recreating the BufferedImage when it is scrolled. Like 99% sure I'll double check.
                          • 10. Re: map coordinate to screen coordinate algorithm
                            796262
                            lessThanNate wrote:
                            kevinaworkman wrote:
                            This is true for scrolling, too. Are you redrawing the entire BufferedImage everytime you move it?
                            Oh and no, I don't think I am recreating the BufferedImage when it is scrolled. Like 99% sure I'll double check.
                            Is the BufferedImage just a static image that you load from a file and then don't modify, or is it generated through code somehow (using Graphics or Graphics2D)?

                            I guess I'm still trying to make sense of how you're trying to draw the NPCs that could be causing so much trouble. Is there any way you could provide some pseudocode, or better yet, an SSCCE ?
                            • 11. Re: map coordinate to screen coordinate algorithm
                              843853
                              kevinaworkman wrote:
                              I guess I'm still trying to make sense of how you're trying to draw the NPCs that could be causing so much trouble. Is there any way you could provide some pseudocode, or better yet, an SSCCE ?
                              Well, its kind of complex and probably set up all wrong so let me just explain as best I can whats going on.

                              First of all Like I said i am trying to make a 2d rpg, but I may want to make it an online multiplayer thing later if I even finish the game. So its a java applet and so far it has two GUI components. What I call the Map an extension of Panel that is in charge of drawing the world that the player moves around on. The other GUI component isn't really important right now its just the console for the game (a text field and a text area you can type in).

                              The map class contains a bunch of other stuff the most important things are, an array of Characters for keeping track of NPCs, as well as possible other players, a PlayerCharacter, and most import is the zone. The zone is a Class I created for storing the map itself, and the constructor reads form a text file to create the map. The text contains stuff like the type of tile (grass, sand w/e) to fill the map with, size of the map, and points of interest like where to draw building, zone lines to other zones, and also where all the npcs start at or spawn at.

                              the Map classes paint function looks like this:
                               public void paint (Graphics g) 
                                  {      
                                      //draw map
                                      g.drawImage(zone.getMapImage(), 0, 0, getWidth(), getHeight(),
                                          player.mapX - getWidth()/2, player.mapY - getHeight()/2 ,
                                          player.mapX + getWidth()/2, player.mapY + getHeight()/2 , this);
                                      
                                      //draw player
                                      g.drawImage(player.getAvatar(), player.x, player.y, this);
                                      
                                      //draw UI
                                      g.setColor(Color.darkGray);
                                      g.fillRect(0, 0, 150, 50);
                                      g.setColor(Color.blue);
                                      g.drawString("Player", 5, 5);
                                      
                                      if (player.getTarget() != null)
                                      {
                                          g.setColor(Color.darkGray);
                                          g.fillRect(155, 0, 150, 50);
                                          g.setColor(Color.blue);
                                          g.drawString(player.getTarget().name, 160, 5);
                                      }
                                      
                                      for (int i = 0; i < npcs.length; i++)
                                      {
                                          if (npcs.isDraw())
                              {
                              g.drawImage(npcs[i].getAvatar(), npcs[i].x, npcs[i].y, this);
                              }
                              }

                              }//end paint()
                              The Character class controls the animation for the sprites with these method  (now don't laugh, lol, this was my first attempt at making a full game and animating sprites so =P)
                              public void move(String com)
                              {
                              int zoneW = inZone.getWidth();
                              int zoneH = inZone.getHeight();
                              int avatW = avat[avatIndex].getWidth();
                              int avatH = avat[avatIndex].getHeight();

                              if ( com.equalsIgnoreCase("up") )
                              {
                              mapY= mapY - 5;
                              if (direction != 6)
                              {
                              time = 0;
                              }
                              direction = 6;
                              if (mapY < 0)
                              {
                              mapY = 0;
                              }
                              }
                              else if ( com.equalsIgnoreCase("right") )
                              {
                              mapX = mapX + 5;
                              if (direction != 9)
                              {
                              time = 0;
                              }
                              direction = 9;
                              if (mapX + avatW > zoneW)
                              {
                              mapX = zoneW - avatW;
                              }
                              }

                              else if ( com.equalsIgnoreCase("down") )
                              {
                              mapY = mapY + 5;
                              if (direction != 0)
                              {
                              time = 0;
                              }
                              direction = 0;
                              //System.out.println("y: " + mapY);
                              //System.out.println("y + avat height: "+ (mapY +avat[avatIndex].getHeight()));
                              if (mapY + avatH > zoneH)
                              {
                              mapY = zoneH - avatH;
                              }
                              }

                              else if ( com.equalsIgnoreCase("left") )
                              {
                              mapX = mapX - 5;
                              if (direction != 3)
                              {
                              time = 0;
                              }
                              direction = 3;
                              if (mapX < 0)
                              {
                              mapX =0;
                              }
                              }

                              startAnimate();
                              }

                              /*
                              *
                              * @see java.lang.Runnable#run()
                              */
                              public void run() {
                              // lower ThreadPriority
                              Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

                              while (/*true */isAnimate)
                              {
                              if (time == 0)
                              {
                              avatIndex = direction;
                              }
                              else if ( time == 3 )
                              {
                              avatIndex = direction + 1;
                              }
                              else if (time == 6)
                              {
                              avatIndex = direction;
                              }
                              else if (time == 9)
                              {
                              avatIndex = direction + 2;
                              }
                              else if (time > 12)
                              {
                              time = -1;
                              }

                              time++;
                              try
                              {
                              // Stop thread for 10 milliseconds
                              Thread.sleep(animationDelay);
                              }
                              catch (InterruptedException e)
                              {
                              e.printStackTrace();
                              }

                              // set ThreadPriority to maximum value
                              Thread.currentThread().setPriority(Thread.MAX_PRIORITY);

                              } //end isAnimate loop
                              tFinished = true;
                              }//end run()

                              public void startAnimate()
                              {
                              isAnimate = true;

                              if (animate == null || tFinished)
                              {
                              animate = new Thread(this);
                              }

                              if (!animate.isAlive())
                              {
                              tFinished = false;
                              animate.start();
                              }
                              else
                              {

                              }
                              }

                              public void stopAnimate()
                              {
                              isAnimate = false;
                              avatIndex = direction;
                              }
                              What you don't see is that "avatIndex" is used by the following method to return the correct sprite image for the animation.
                              public Image getAvatar()
                              {
                              return avat[avatIndex];
                              //return sheet;
                              }
                              Its not giving me too much trouble to draw the NPCs, when I had problems with drawing NPCs to the map image I just figured it would be best to drawing on the screen and not the map.  But I couldn't figure out how to translate the two coordinate systems.
                              
                              This post may confuse readers a lot lol,  so possibly just forget you asked.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
                              • 12. Re: map coordinate to screen coordinate algorithm
                                843853
                                Sorry that definitely wasn't short, self contained, or compilable lol.
                                • 13. Re: map coordinate to screen coordinate algorithm
                                  843853
                                  montsie wrote:
                                  Imagin the map and screen are the same size then the map coordinates are equals the screen coordinates...

                                  If the screen is smaller as the map then you need to know some screenX, screenY which told you where the screen
                                  is on your map. screenX and screenY are set by your scroll code (or key up/down/left/right...)

                                  Now to get 1) the map coordinate from the screen coordinate (or 2) screen coordinate from the map coordinate)
                                  is easy...


                                  E.g..

                                  1)
                                  int playerMapX = playerScreenX + screenX;int playerMapY = playerScreenY + screenY;
                                  2) ...
                                  That was the answer thanks for the help both of you.