3

Currently I am trying to make an agar.io like game, and I am having problems with scrolling and viewports. Here is my code:

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Toolkit;

import javax.swing.JFrame;

public class Game extends Applet{

    public void paint (Graphics g)
    {
        Player p = new Player("test");
        int centerX = p.getPos()[0];
        int centerY = p.getPos()[1];
        String name = p.getName();
        int fontSize = (int)Math.round(20 - name.length() / 1.5);
        for(int i = 0; i < p.getCells().length; i++){
            g.setFont(new Font("Monospaced", Font.BOLD, fontSize));
            g.setColor(p.getColor());
            g.fillOval(p.getPos()[0] - p.getCells()[i].getMass() / 2, p.getPos()[1] - p.getCells()[i].getMass() / 2, p.getCells()[i].getMass(), p.getCells()[i].getMass());
            g.setColor(new Color(0, 0, 0));
            g.drawString(p.getName(), (int)Math.round(centerX - name.length() * Math.round(fontSize / 3)), centerY + Math.round(fontSize / 3));
        }
    }

    public static void main(String args[])
    {
        Game a = new Game();
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        JFrame frame = new JFrame();    
        frame.setSize(100000, 100000); 
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(a, BorderLayout.CENTER);
        frame.setVisible(true);
    }
}

This is the Player object code:

import java.awt.Color;

public class Player {
    private int cellNumber, score;
    private String name;
    private Cell[] cells;
    private Color color = new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255));
    public Player(){
        name = "An unnamed cell";
        cellNumber = 1;
        cells = new Cell[]{new Cell()};
    }
    public Player(String n){
        name = n;
        cellNumber = 1;
        cells = new Cell[]{new Cell()};
    }
    public void setName(String n){
        name = n;
    }
    public void setCellNumber(int n){
        cellNumber = n;
    }
    public void setCells(Cell[] n){
        cells = n;
    }
    public String getName(){
        return name;
    }
    public int getCellNumber(){
        return cellNumber;
    }
    public Cell[] getCells(){
        return cells;
    }
    public int getScore(){
        int sum = 0;
        for(Cell c : cells) sum += c.getMass();
        return sum;
    }
    public int[] getPos(){
        int sumX = 0;
        for (Cell c : cells) sumX += c.getX();
        int avgX = Math.round(sumX / cells.length);
        int sumY = 0;
        for (Cell c : cells) sumY += c.getY();
        int avgY = Math.round(sumY / cells.length);
        return new int[]{avgX, avgY};
    }
    public Color getColor(){
        return color;
    }
}

The Cell object Code:

public class Cell {
    private int xCoor, yCoor, mass;
    public Cell(){
        xCoor = (int)(Math.random() * 10000);
        yCoor = (int)(Math.random() * 10000);
        mass = 100;
    }
    public void setX(int x){
        xCoor = x;
    }
    public void setY(int y){
        yCoor = y;
    }
    public void setMass(int m){
        mass = m;
    }
    public int getX(){
        return xCoor;
    }
    public int getY(){
        return yCoor;
    }
    public int getMass(){
        return mass;
    }
}

This picture is a good representation of what I want.

enter image description here

Basically, what is drawn by paint is shown across the entire JFrame (which I think I already achieved, correct me if I'm wrong) but I only want to user to be able to view a small part of it.

I believe that to do this, you need to use a JViewPort and JScrollPane, but I don't know how to implement that into my code. Any help with that would be greatly appreciated.

Touchstone
  • 5,575
  • 7
  • 41
  • 48
  • I don't think this will work. You should display the graphics in a panel, and then scroll across the panel with a viewport. Anyways, you may want to abandon the viewport thing and just implement the scroll differently –  Jan 05 '16 at 01:58
  • `public class Game extends Applet{ .. Game a = new Game(); .. JFrame frame = new JFrame(); .. frame.getContentPane().add(a, BorderLayout.CENTER);` Nope. Best to dump the `Applet` & instead extend a `JComponent` like `JPanel`. Override the `paintComponent(Graphics)` method instead of `paint(..)` & immediately call the `super` method. – Andrew Thompson Jan 05 '16 at 02:04
  • `g.drawString(p.getName(), (int)Math.round(centerX - name.length() ..` Umm.. no. Since `name` is a `String` that number will be the number of characters in the string, rather than the number of pixels wide. – Andrew Thompson Jan 05 '16 at 02:07
  • Why are you using an applet? Why are you overriding paint? Why are you breaking the paint chain? Seriously, I honk you have bigger problems to solve first – MadProgrammer Jan 05 '16 at 02:08
  • `for(int i = 0; i < p.getCells().length; i++){ g.setFont(new Font("Monospaced", Font.BOLD, fontSize));` 1) The font should be created outside the loop. 2) Change `"Monospaced"` to `Font.MONOSPACED` for compile time checking. 3) `new Color(0, 0, 0)` is equivalent to `Color.BLACK` ;) – Andrew Thompson Jan 05 '16 at 02:12
  • 1
    For [example](http://stackoverflow.com/questions/16050723/java-applet-game-2d-window-scrolling/16052048#16052048) and [example](http://stackoverflow.com/questions/25419808/frames-painting-at-different-times/25423804#25423804) – MadProgrammer Jan 05 '16 at 02:13
  • I don't think you can use Applet and JFrame together. You have to pick one or the other to be your top level component. If you are using applets (dodgy, Chrome no long supports Java applets, and other browsers have been making bad noises about applets for some time now), you must use Applet or JApplet. – markspace Jan 05 '16 at 03:04
  • 1
    @AndrewThompson Thanks for the tips! I will be sure to ditch the applet and use a JPanel instead. As for drawing the string, I understand that it returns the length of the String, but I am using that as a ratchet way to center the text inside of the circle. It works for my purpose, but is there a better way to do that? Thanks! – Scott Jacobsen Jan 05 '16 at 04:06
  • *"..is there a better way to do that?"* No! There are **many** better ways to do it. I usually get a `Shape` of the visual representation of the `String`. E.G. as seen [here](http://stackoverflow.com/a/6296381/418556).. – Andrew Thompson Jan 05 '16 at 12:10

1 Answers1

1

I had a similar situation to yours and I implemented something like this. I don't know if it's ideal and would appreciate it if someone can verify. It did do the job I was looking for however a slow frame rate did not help.

import javax.swing.*;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

public class MovingAnimationJava7 extends Canvas {
    
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private BufferedImage canvas;
    private JViewport viewport;
    

    public MovingAnimationJava7(int width, int height) {
        canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    }
    
    public void start() {
        Thread.currentThread();
        int i = 0;
        while(true) {
            try {
                repaint();
                Point point = new Point(i,i++);
                viewport.setViewPosition(point);
                Thread.sleep(100);
            }
            catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void paint(Graphics g) {
        Random r = new Random();
        for (int x = 0; x < canvas.getWidth(); x++) {
            for (int y = 0; y < canvas.getHeight(); y++) {
                int red=r.nextInt(256);
                int green=r.nextInt(256);
                int blue=r.nextInt(256);
                Color c=new Color(red,green,blue);
                int color = c.getRGB();
                canvas.setRGB(x, y, color);
            }
        }
        
        Graphics2D g2 = (Graphics2D) g;
        g2.drawImage(canvas, null, null);
    }
    
    private JViewport getVP() { return viewport; }
    private void setVP(JViewport vp) { viewport = vp; }

    public static void main(String[] args) {
        MovingAnimationJava7 animatedCanvas = new MovingAnimationJava7(400,400);
        
        JViewport viewport = new JViewport();
        viewport.setSize(159, 143);
        viewport.add(animatedCanvas);
        Point point = new Point(0,0);
        viewport.setViewPosition(point);
        animatedCanvas.setVP(viewport);
        
        JFrame jp = new JFrame();
        jp.getContentPane().add(animatedCanvas.getVP(), BorderLayout.CENTER);
        jp.setSize(new Dimension(500,500));
        jp.setVisible(true);
        animatedCanvas.start();
    }
}
Faiz
  • 133
  • 1
  • 6