0
\$\begingroup\$

After making some progress in my game, I was looking around for camera scrolling methods to use for my TDS game and found one that I thought would work well for it.

This is an example of what sort of scrolling I want: enter image description here

The creator of the document called it a target-focus camera (I do not know if there is an official name for it), and I was wondering how to create camera scrolling like that featured in the example and if anyone has examples that I can look at to see how it works and such.

Please note that there are quite a few things in here that will be removed due to not being needed. Most of them are the "is never used" stuff.

Player class.

    import java.awt.*;
    import javax.swing.*;
    import java.awt.image.*;
    import javax.imageio.*;
    import java.io.*;
    import java.awt.event.MouseEvent;
    import java.lang.Math;

   public class Player 
    {
    // prototype of the mouse location information.
     PointerInfo a = MouseInfo.getPointerInfo();
     Point b = a.getLocation();
     int mX = (int)b.getX();
     int mY = (int)b.getY();



     private int xPos, yPos, r;
     int dist = 1;
     //information on what part of the world the player is at.
     private int secX,secY;





private int dx,dy;
//speed will depend on what ship Player is using and what items it has.
private int speed;
//   private int xLoc, yLoc;
//  private Sector location;



//prototype variables to dictate where the camera will center
int cX = (mX - xPos) * dist + xPos;
int cY = (mY - yPos) * dist + yPos;

private String userName;

 private Ship ship;
// private Weapon weapon;
// private Engine engine;
private boolean left;
private boolean right;
private boolean up;
private boolean down;
//  private boolean firing;

private Color color1;
private Color color2;
// Variable to use when finding the angle needed to turn.
private double angleToTurn;
double mx, my;

public Player(Ship s){
 setShip(s);
 //  x = GameData.WIDTH / 2;
  //  y = GameData.HEIGHT / 2;
 xPos = s.getX();
 yPos = s.getY();
 r = s.getR();


    dx = 0;
    dy = 0;
    speed = 5;


    color1 = Color.WHITE;
    color2 = Color.RED;

  //  firing = false;
  //  firingTimer = System.nanoTime();
  //  firingDelay = 200;

  //   recovering = false;
  //  recoveryTimer = 0;

 //   score = 0;
    }

public void setShip(Ship s){
ship = s;
}



//  public int getXLoc(){return xLoc;}
 //   public int getYLoc(){return yLoc;}
 //   public Sector getLocation(){return location;}
public int getx() { return xPos; }
public int gety() {return yPos;}
public int getr() { return r; }

 public void setLeft(boolean b) { left = b; }
 public void setRight(boolean b) { right = b; }
 public void setUp(boolean b) { up = b; }
 public void setDown(boolean b) { down = b; }


 //TODO Add controls for mouse based on what class of ship it is.   
  public void update() {

    if(left) {
        dx = -speed;
    }
    if(right) {
        dx = speed;
    }
    if(up) {
        dy = -speed;
    }
    if(down) {
        dy = speed;
    }

    xPos += dx;
    yPos += dy;

    if(xPos < ship.getX2() ){ 

      xPos = ship.getX2();
   } 
    if(yPos    < ship.getY2()  ){ 
      yPos = ship.getY2();

    } 


    if(xPos > GameData.WIDTH - r){xPos = GameData.WIDTH - r;
     }
    if(yPos > GameData.HEIGHT - r){
    yPos = GameData.HEIGHT - r;

    } 

    dx = 0;
    dy = 0;

    // firing
    /*
     if(firing){long elapsed = (System.nanoTime() - firingTimer) / 1000000;
        GamePanel.bullets.add(new Bullet(270, x, y));
     if(elapsed > firingDelay) {



        firingTimer = System.nanoTime();



        }






    }
   */



    /*
    if(recovering) {
        long elapsed = (System.nanoTime() - recoveryTimer) / 1000000;
        if(elapsed > 2000) {
            recovering = false;
            recoveryTimer = 0;
        }
    }
    */


}

 public void draw(Graphics2D g) {


    g.drawImage(ship.buff, xPos, yPos, null);


    /*
         g.setColor(color1);
        g.fillOval(x - r, y - r, 2 * r, 2 * r);

        g.setStroke(new BasicStroke(3));
        g.setColor(color1.darker());
        g.drawOval(x - r, y - r, 2 * r, 2 * r);
        g.setStroke(new BasicStroke(1));
    */


}


public void moveToNextLoc(Sector m){}

//TODO add mouse rotation to the player (to start out with)
}

GameData

import javax.swing.JPanel;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.util.*;
//import javax.swing.*;
//import javax.imageio.*;
//import java.io.*;

import java.awt.event.MouseEvent;
//import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;


public class GameData extends JPanel implements Runnable, KeyListener, MouseMotionListener
{
// instance variables - replace the example below with your own
  //   MouseListener mouse = new MouseMotionListener();
  Point playerPoint;
  Point turretPoint;

public static int WIDTH = 400;
public static int HEIGHT = 400; // stuff here may change
public static int MINWIDTH = 0;
public static int MINHEIGHT = 0; 
private int FPS = 30;
// private double averageFPS;
private Thread thread;
private boolean running;

private BufferedImage image;
private Graphics2D g;


public static Player userPlayer;
public static ArrayList<Bullet> bullets;
public static ArrayList<Text> texts;




 //  float angle = (float)(Math.atan2(userPlayer.gety() - mouse.y, userPlayer.getx() - mouse.x));
 public GameData() {
 super();
 setPreferredSize(new Dimension(WIDTH, HEIGHT));
 setFocusable(true);
 requestFocus();

 }

public void addNotify() {
super.addNotify();
if(thread == null) {
thread = new Thread(this);
thread.start();
}
addKeyListener(this);
}

public void run() {

this.requestFocus();
running = true;

image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
g.setRenderingHint(
 RenderingHints.KEY_ANTIALIASING,
 RenderingHints.VALUE_ANTIALIAS_ON);
 g.setRenderingHint(
 RenderingHints.KEY_TEXT_ANTIALIASING,
 RenderingHints.VALUE_TEXT_ANTIALIAS_ON);



userPlayer = new Player(sampleShip);
//bullets = new ArrayList<Projectile>();
//enemies = new ArrayList<Enemy>();
//powerups = new ArrayList<PowerUp>();
//explosions = new ArrayList<Explosion>();
texts = new ArrayList<Text>();



long startTime;
long URDTimeMillis;
long waitTime;
long totalTime = 0;

int frameCount = 0;
int maxFrameCount = 30;

long targetTime = 1000 / FPS;

//hue = 0;

// GAME LOOP
while(running) {

startTime = System.nanoTime();

gameUpdate();
gameRender();
gameDraw();

URDTimeMillis = (System.nanoTime() - startTime) / 1000000;

waitTime = targetTime - URDTimeMillis;

try {
Thread.sleep(waitTime);
}
catch(Exception e) {
}

frameCount++;
if(frameCount == maxFrameCount) {
//   averageFPS = 1000.0 / ((totalTime / frameCount) / 1000000);
 frameCount = 0;
totalTime = 0;
}

}

g.setColor(new Color(0, 100, 255));
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.WHITE);
g.setFont(new Font("Century Gothic", Font.PLAIN, 16));
String s = "G A M E   O V E R";
int length = (int) g.getFontMetrics().getStringBounds(s, g).getWidth();
g.drawString(s, (WIDTH - length) / 2, HEIGHT / 2);
//  s = "Final Score: " + userPlayer.getScore();
length = (int) g.getFontMetrics().getStringBounds(s, g).getWidth();
g.drawString(s, (WIDTH - length) / 2, HEIGHT / 2 + 30);
gameDraw();

}

private void gameUpdate() {

 // new wave


  // create enemies
  /*
   if(waveStart && enemies.size() == 0) {
   createNewEnemies();
   }
   */
  // player update
  userPlayer.update();

  // bullet update
  /*
   for(int i = 0; i < bullets.size(); i++) {
   boolean remove = bullets.get(i).update();
   if(remove) {
   bullets.remove(i);
   i--;
   }
   }
   */




  /*
   // enemy update
   for(int i = 0; i < enemies.size(); i++) {
   enemies.get(i).update();
   }
   */
  // powerup update

  /*
   for(int i = 0; i < powerups.size(); i++) {
   boolean remove = powerups.get(i).update();
   if(remove) {
   powerups.remove(i);
   i--;
   }
   }
   */

  /*
   * 
   // explosion update
   for(int i = 0; i < explosions.size(); i++) {
   boolean remove = explosions.get(i).update();
   if(remove) {
   explosions.remove(i);
   i--;
   }
   }

   */


  // text update

  for(int i = 0; i < texts.size(); i++) {
    boolean remove = texts.get(i).update();
    if(remove) {
      texts.remove(i);
      i--;
    }
  }

  // bullet-enemy collision

  /*
   for(int i = 0; i < bullets.size(); i++) {

  Bullet b = bullets.get(i);
  double bx = b.getx();
  double by = b.gety();
  double br = b.getr();

   for(int j = 0; j < enemies.size(); j++) {

   Enemy e = enemies.get(j);
   double ex = e.getx();
   double ey = e.gety();
   double er = e.getr();

   double dx = bx - ex;
   double dy = by - ey;
   double dist = Math.sqrt(dx * dx + dy * dy);

   if(dist < br + er) {
   e.hit();
   bullets.remove(i);
   i--;
   break;
   }

   }

   }
   */

   /*
  // check dead enemies
  for(int i = 0; i < enemies.size(); i++) {

  if(enemies.get(i).isDead()) {

   Enemy e = enemies.get(i);

  // chance for powerup
  double rand = Math.random();
  if(rand < 0.001) powerups.add(new PowerUp(1, e.getx(), e.gety()));
  else if(rand < 0.020) powerups.add(new PowerUp(3, e.getx(), e.gety()));
  else if(rand < 0.120) powerups.add(new PowerUp(2, e.getx(), e.gety()));
  else if(rand < 0.130) powerups.add(new PowerUp(4, e.getx(), e.gety()));

  player.addScore(e.getType() + e.getRank());
  enemies.remove(i);
  i--;

  e.explode();
  explosions.add(new Explosion(e.getx(), e.gety(), e.getr(), e.getr() + 30));

  }

  }
  */
  // check dead player
  /*
 if(userPlayer.isDead()) {
 running = false;
 }
 */



  // player-enemy collision
  /*
 if(!player.isRecovering()) {
 int px = player.getx();
 int py = player.gety();
 int pr = player.getr();
 for(int i = 0; i < enemies.size(); i++) {

 Enemy e = enemies.get(i);
 double ex = e.getx();
 double ey = e.gety();
 double er = e.getr();

 double dx = px - ex;
 double dy = py - ey;
 double dist = Math.sqrt(dx * dx + dy * dy);

  if(dist < pr + er) {
   player.loseLife();
  }

  }
  }
  */
  // player-powerup collision
  /*
  int px = player.getx();
  int py = player.gety();
  int pr = player.getr();

  for(int i = 0; i < powerups.size(); i++) {
  PowerUp p = powerups.get(i);
  double x = p.getx();
  double y = p.gety();
  double r = p.getr();
  double dx = px - x;
  double dy = py - y;
  double dist = Math.sqrt(dx * dx + dy * dy);

  // collected powerup
  if(dist < pr + r) {

   int type = p.getType();

   if(type == 1) {
   player.gainLife();
   texts.add(new Text(player.getx(), player.gety(), 2000, "Extra Life"));
   }
   if(type == 2) {
   player.increasePower(1);
   texts.add(new Text(player.getx(), player.gety(), 2000, "Power"));
   }
   if(type == 3) {
   player.increasePower(2);
   texts.add(new Text(player.getx(), player.gety(), 2000, "Double Power"));
   }
   if(type == 4) {
   slowDownTimer = System.nanoTime();
   for(int j = 0; j < enemies.size(); j++) {
   enemies.get(j).setSlow(true);
   }
   texts.add(new Text(player.getx(), player.gety(), 2000, "Slow Down"));
   }

   powerups.remove(i);
   i--;

   }

   }
   */



    }


     private void gameRender() {

    // draw background
       g.setColor(new Color(0, 100, 255));
       g.fillRect(0, 0, WIDTH, HEIGHT);

       // draw slowdown screen


       // draw player
       userPlayer.draw(g);

       // draw bullet

       /*
        for(int i = 0; i < bullets.size(); i++) {
        bullets.get(i).draw(g);
        }

        // draw enemy
        for(int i = 0; i < enemies.size(); i++) {
        enemies.get(i).draw(g);
        }

        // draw powerups
        /*
        for(int i = 0; i < powerups.size(); i++) {
        powerups.get(i).draw(g);
        }
        */
       /*
        // draw explosions
        for(int i = 0; i < explosions.size(); i++) {
        explosions.get(i).draw(g);
        }

        // draw text
        for(int i = 0; i < texts.size(); i++) {
        texts.get(i).draw(g);
        }



          // draw player lives
          for(int i = 0; i < player.getLives(); i++) {
          g.setColor(Color.WHITE);
          g.fillOval(20 + (20 * i), 20, player.getr() * 2, player.getr() * 2);
          g.setStroke(new BasicStroke(3));
          g.setColor(Color.WHITE.darker());
          g.drawOval(20 + (20 * i), 20, player.getr() * 2, player.getr() * 2);
           g.setStroke(new BasicStroke(1));
           }

           // draw player power
           g.setColor(Color.YELLOW);
           g.fillRect(20, 40, player.getPower() * 8, 8);
           g.setColor(Color.YELLOW.darker());
           g.setStroke(new BasicStroke(2));
           for(int i = 0; i < player.getRequiredPower(); i++) {
           g.drawRect(20 + 8 * i, 40, 8, 8);
           }
           g.setStroke(new BasicStroke(1));

           // draw player score
           g.setColor(Color.WHITE);
           g.setFont(new Font("Century Gothic", Font.PLAIN, 14));
           g.drawString("Score: " + player.getScore(), WIDTH - 100, 30);
           */



              }


            private void gameDraw() {
              Graphics g2 = this.getGraphics();
              g2.drawImage(image, 0, 0, null);
              g2.dispose();
             //  adapter.render(g);
            }


            public void keyTyped(KeyEvent key) {}
            public void keyPressed(KeyEvent key) {
              int keyCode = key.getKeyCode();
              if(keyCode == KeyEvent.VK_LEFT) {
                userPlayer.setLeft(true);
              }
              if(keyCode == KeyEvent.VK_RIGHT) {
                userPlayer.setRight(true);
              }
              if(keyCode == KeyEvent.VK_UP) {
                userPlayer.setUp(true);
              }
              if(keyCode == KeyEvent.VK_DOWN) {
                userPlayer.setDown(true);
              }
              /*
               if(keyCode == KeyEvent.VK_Z) {
               userPlayer.setFiring(true);
               }
               */
            }
            public void keyReleased(KeyEvent key) {
              int keyCode = key.getKeyCode();
              if(keyCode == KeyEvent.VK_LEFT) {
                userPlayer.setLeft(false);
              }
              if(keyCode == KeyEvent.VK_RIGHT) {
                userPlayer.setRight(false);
              }
              if(keyCode == KeyEvent.VK_UP) {
                userPlayer.setUp(false);
              }
              if(keyCode == KeyEvent.VK_DOWN) {
                userPlayer.setDown(false);
              }
              /*
               if(keyCode == KeyEvent.VK_Z) {
               userPlayer.setFiring(false);
               }
               */
            }
            // for mouse. MOUSE PROGRESS FTW!

            public void mouseClicked(MouseEvent e) {

            }
            public void mouseExited(MouseEvent e) {

            }
            public void mouseEntered(MouseEvent e) {


            }
            public void mousePressed(MouseEvent e) {
    playerPoint = e.getPoint();
     float angle = (float)(Math.atan2(userPlayer.gety() - playerPoint.y, userPlayer.getx() - playerPoint.x));
    int x = e.getX();
    int y = e.getY();
            }
            public void mouseReleased(MouseEvent e) {
     playerPoint = null;

            }
            public void mouseMoved(MouseEvent e) {
              int x = e.getX();
              int y = e.getY();
              float angle = (float)(Math.atan2(userPlayer.gety() - playerPoint.y, userPlayer.getx() - playerPoint.x));
   // ^^^ p used to be mouse so watch out on that.
    }
            public void mouseDragged(MouseEvent e) {
  turretPoint = e.getPoint();
    float angle = (float)(Math.atan2(userPlayer.gety() - turretPoint.y, userPlayer.getx() - turretPoint.x));
            }   


            Ship sampleShip = new Ship(83,83,83,0,0,false,"C:\\Users\\Kenny\\Desktop\\ProjectProto\\ProtoGame\\Proto\\Images\\Ships\\ATN_FIGHTER_LOWRES.PNG");
           //TODO: have file directory change to allow other devices to be able to get the files.
    }

Camera.

  import java.awt.*;





  public class Camera{
  private int x,y;
  private Player player;
  private int xPos, yPos;
  MapSector sec;
   GameData data;
  public  int xmax = sec.XSIZE;
  public int ymax = sec.YSIZE;
  public int dist = 1;
  // prototype of the mouse location information.
  private  PointerInfo a;
  private Point b;
  private int mX,mY,cX,cY;
 private int dirX

  public int xView;
  public int yView;

  //Location of the center of an Image
  private  int iX, iY;
  public Camera(int x, int y, Player player, int xPos,int yPos){
    this.x = x;
    this.y = y;
    this.player = player;
    xPos = player.getx();
    yPos = player.gety();
    xView = data.WIDTH;
    yView = data.HEIGHT;
    iX = player.ship.img.getCenterX();
    iY = player.ship.img.getCenterY();
  }

  public int getX(){return x;}
  public int getY(){return y;}

  public void setX(int x){this.x = x;}
  public void setY(int y){this.y = y;}

  public void updateCamera(){
    a = MouseInfo.getPointerInfo();
    b = a.getLocation();
    mX = (int)b.getX();
    mY = (int)b.getY();
    cX = (mX - xPos) * dist + xPos;
    cY = (mY - yPos) * dist + yPos;
  }

  public void defaultCamera(){
    cX = iX;
    cY = iY;
  }
\$\endgroup\$
1
\$\begingroup\$

Lets start of by defining a few variables. Lets say that o is the position of the player, d is the point that we want the player to look at, c is the position of the camera and dist is how much do we want to move c towards d, were dist is a float between 0 and 1.

float cX = (dX - oX) * dist + oX;
float cY = (dY - oY) * dist + oY;

In case you want to move smoothly towards that point you can use the following method, where L the previous camera position, C is the one we just calculates using the method above, out is the smooth position, and minDist the distance from C that when reached the camera will stop moving:

float dirX = (cX - lX);
float dirY = (cY - lY);
float length = (float)Math.sqrt(dirX * dirX + dirY * dirY) - 0.6f;
dirX /= length;
dirY /= length;
dirX *= delta;
dirY *= delta;
float outX = lX + dirX;
float outY = lY + dirY;

In sum, all of the above would look something like this:

float cX = (dX - oX) * dist + oX;
float cY = (dY - oY) * dist + oY;

float dirX = (cX - lX);
float dirY = (cY - lY);
float length = (float)Math.sqrt(dirX * dirX + dirY * dirY) - 0.6f;

float outX = lX;
float outY = lY;

if(length > minDist) {
    dirX /= length;
    dirY /= length;
    dirX *= delta + 0.5f;
    dirY *= delta + 0.5f;
    outX = lX + dirX;
    outY = lY + dirY;
}

Now, in your case there are a few things you should change:

public void updateCamera(){
 a = MouseInfo.getPointerInfo();
 b = a.getLocation();
 mX = (int)b.getX();
 mY = (int)b.getY();
 cX = (mX - xPos) * dist + xPos;
 cY = (mY - yPos) * dist + yPos;

 float dirX = (cX - lX);
 float dirY = (cY - lY);
 float length = (float)Math.sqrt(dirX * dirX + dirY * dirY) - 0.6f;

 float outX = lX;
 float outY = lY;

 if(length > minDist) {
     dirX /= length;
     dirY /= length;
     dirX *= delta + 0.5f;
     dirY *= delta + 0.5f;
     outX = lX + dirX;
     outY = lY + dirY;
 }
 x = (int)outX;
 y = (int)outY;
}

Also, before you ask: I have taken a look at your code and haven't found the camera being used anywhere. So I thought you were having problems with that as well. Here is a solution: You can add an x and y offset to the position of every thing that is rendered, like entities and the player, but not the UI. And in each update you set that x and y offset to the negative x and y position of the camera. In that way the world will move around, creating the feeling that there is a camera.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Comments are not for extended discussion; this conversation has been moved to chat. \$\endgroup\$ – DMGregory Oct 10 '18 at 15:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.