Note that I have found a similar post here, but this question seems to be having this problem consistantly and didn't really offer an explination as to WHY this occurs, only an alternate approach.
I'm creating a Stratego game, and right now I am creating boards where a play can swap around their pieces and then submit the board layout as their army starting locations.
I have a single JButton on each of the frames (one for each player, the second shows up after the first player has submited and left the computer), and the JButton on the first frame only is hidden until you hover it, but only the first time that the program runs after Eclipse is opened.
Can someone give an explination as to why this occurs?
The Main running class
LogicInterpreter logic = new LogicInterpreter();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
InputFrame inputPlayer1 = new InputFrame(logic, 1, "red", 600, 600);
inputPlayer1.setLocation(dim.width / 2 - inputPlayer1.getSize().width/2,
dim.height / 2 - inputPlayer1.getSize().height / 2);
while(!logic.isSetUp1()){
//Just to make it work
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//Now bring up board 2
InputFrame inputPlayer2 = new InputFrame(logic, 2, "blue", 600, 600);
inputPlayer2.setLocation(dim.width / 2 - inputPlayer2.getSize().width/2,
dim.height / 2 - inputPlayer2.getSize().height / 2);
while(!logic.isSetUp2()){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//Will eventually open the main board
openBoards(logic);
}
This is the relevant setup code for the input frames
public class InputFrame extends JFrame {
private static final long serialVersionUID = 1L;
private LogicInterpreter holder;
private Panel2 jp;
private int height, width;
private Map<Integer, ArrayList<Integer>> lakeCoords = new HashMap<>();
private List<Piece> pieces = new ArrayList<>();
private int playernumber;
private String playerColor;
Piece selectedPiece;
Piece secondSelectedPiece;
boolean hidePieces = false;
JButton submit = new JButton("SUBMIT");
public void addCoords() {
lakeCoords.put(3, new ArrayList<Integer>(Arrays.asList(6, 5)));
lakeCoords.put(4, new ArrayList<Integer>(Arrays.asList(6, 5)));
lakeCoords.put(7, new ArrayList<Integer>(Arrays.asList(6, 5)));
lakeCoords.put(8, new ArrayList<Integer>(Arrays.asList(6, 5)));
}
public void createPieces() {
int y = 1;
if (playernumber == 2) {
y = 6;
}
List<Integer> openValues = new ArrayList<>();
openValues.add(1);
openValues.add(2);
openValues.add(11);
openValues.add(12);
for (int x = 0; x < 2; x++) {
openValues.add(3);
}
for (int x = 0; x < 3; x++) {
openValues.add(4);
}
for (int x = 0; x < 4; x++) {
openValues.add(5);
openValues.add(6);
openValues.add(7);
}
for (int x = 0; x < 5; x++) {
openValues.add(8);
}
for (int x = 0; x < 8; x++) {
openValues.add(9);
}
for (int x = 0; x < 6; x++) {
openValues.add(10);
}
Collections.sort(openValues);
for (int x = 1; x <= 10; x++) {
for (int z = y; z <= 4; z++) {
// 1x1 Marshal
// 2x1 General
// 3x2 Colonel
// 4x3 Major
// 5x4 Captain
// 6x4 Lieutenant
// 7x4 Sergeant
// 8x5 Miner
// 9x8 Scout
// 10x6 Bomb
// 11x1 Flag
// 12x1 Spy
Piece piece = new Piece(new Coords(x, z), openValues.get(0), playerColor);
openValues.remove(0);
pieces.add(piece);
}
}
}
public InputFrame(LogicInterpreter holder, int playerNumber, String playerColor, int height, int width) {
this.height = height;
this.width = width;
playernumber = playerNumber;
this.playerColor = playerColor;
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
addCoords();
this.holder = holder;
createPieces();
jp = new Panel2(height, width);
setResizable(false);
jp.setBackground(new Color(235, 202, 158));
setTitle("Player " + playerNumber + " Arrangement GUI || Click Submit When Ready");
jp.setPreferredSize(new Dimension(600, 600));
jp.setLayout(null);
jp.addMouseListener(new HandleMouse());
getContentPane().add(jp);
pack();
setVisible(true);
if(playernumber == 1)
submit.setBounds(width / 10 * 4, height / 10 * 7, width / 10 * 2, height / 10 * 2);
else
submit.setBounds(width / 10 * 4, height / 10, width / 10 * 2, height / 10 * 2);
submit.setFont(new Font("Arial", Font.BOLD, width * 20 / 600));
submit.setBackground(Color.LIGHT_GRAY);
submit.addActionListener(new CloseListener(this));
jp.add(submit);
}
//More stuff down here about logic and stuff
public class Panel2 extends JPanel {
private static final long serialVersionUID = 1L;
int height = 0;
int width = 0;
public Panel2(int height, int width) {
this.height = height;
this.width = width;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int x = 0; x < width; x += width / 10) {
for (int y = 0; y < height; y += height / 10) {
boolean fill = false;
for (Entry<Integer, ArrayList<Integer>> coords : lakeCoords.entrySet()) {
if ((coords.getKey() - 1 == x / 60 && coords.getValue().get(0) - 1 == y / 60)
|| (coords.getKey() - 1 == x / 60 && coords.getValue().get(1) - 1 == y / 60)) {
fill = true;
break;
}
}
if (fill) {
g.setColor(Color.BLUE);
g.fillRect(x, y, width / 10, height / 10);
g.setColor(Color.BLACK);
g.drawRect(x, y, width / 10, height / 10);
} else {
g.setColor(Color.BLACK);
g.drawRect(x, y, width / 10, height / 10);
}
}
}
if(hidePieces){
for (Piece piece : pieces) {
try {
g.drawImage(ImageIO.read(new File(playerColor + "_pieces/" + (playerColor.equals("blue") ? "Blue" : "Red") + "_Strat_Piece"
+ ".png")), piece.getX() * width / 10 - width / 10,
piece.getY() * height / 10 - height / 10, width / 10, height / 10, null);
} catch(Exception e){}
}
} else {
for (Piece piece : pieces) {
g.drawImage(piece.getImage(), piece.getX() * width / 10 - width / 10,
piece.getY() * height / 10 - height / 10, width / 10, height / 10, null);
}
if (selectedPiece != null) {
g.setColor(Color.BLUE);
g.drawImage(selectedPiece.getImage(), selectedPiece.getX() * width / 10 - width / 10,
selectedPiece.getY() * height / 10 - height / 10, width / 10, height / 10, null);
g.drawRect(selectedPiece.getX() * width / 10 - width / 10,
selectedPiece.getY() * height / 10 - height / 10, width / 10, height / 10);
}
}
}
}
setVisible(true);
....
jp.add(submit); // Note the add() is after the setVisible()
and the JButton on the first frame only is hidden until you hover it, but only the first time that the program runs after Eclipse is opened.
This implies that you are making the frame visible BEFORE adding all the components to the frame.
So the order of the basic logic is:
JPanel panel = new JPanel();
panel.add(...);
frame.add(panel);
frame.pack();
frame.setVisible(true);
Swing components have to be created in EDT. Calling sleep() is EDT will block the UI and is never a good idea. See this for details on EDT: https://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html
Related
I'm trying to make a java GUI game version of the game called " jump it" (http://www.crazygames.com/game/jump-it). I am currently on the part of drawing randomized rectangles for my character to jump on. However, I don't know how to continuously draw more rectangles since I'm fairly new to GUI. So my code is below and I hope you guys can help me!
class BtnActPanel extends JPanel implements
ActionListener{
private int x = 0,
x1 = 650,
y2 = (int)(Math.random()*100)+40,
y1 = (int)(Math.random()*100)+450,
x2 = (int)(Math.random()*600)+200;
.
.
.
}
public void actionPerformed(ActionEvent e) {
.
.
.
else if (e.getSource() == b3){
JOptionPane.showMessageDialog(null, "This is an exit button, hope you enjoyed the game! :)", "Exit message",JOptionPane.WARNING_MESSAGE ); //shows exit message
System.exit(0);//exits program
}
else if (e.getSource() == t){
if (index == 0){
index = 1;
c = arrImage[1];
}
else{
index = 0;
c = arrImage[0];
}
x = x-10;
x1 = x1-10;
repaint();
}
}
public void paintComponent(Graphics g){//this method draws and paints images and icons based on the user decisions
super.paintComponent(g);
if(check1 == 0)
g.drawImage(icon.getImage(),0,0,null);
if(check1 == 1){
g.drawImage(b.getImage(),0,0,null);
g.setColor(Color.black);
g.fillRect(x,495, 500, 35);
g.fillRect(x1, y1, x2, y2);
g.drawImage(c.getImage(), 100, 460, null);
}
if(check1 == 2)
g.drawImage(instruct.getImage(),0,0,null);
b1.setBounds(320, 350, 100, 100);
b2.setBounds(420, 350, 100, 100);
b3.setBounds(520, 350, 100, 100);
}
}//end of class
You can set a timer or generate some in a loop.
You can adjust the thresholds as you see fit.
static Random r = new Random();
static int upperX = 100;
static int lowerX = 20;
static int upperY = 100;
static int lowerY = 50;
static int minWidth = 100;
static int maxWidth = 300;
static int minHeight = 50;
static int maxHeight = 200;
public static Rectangle newRect() {
// All ranges inclusive of thresholds
int x = r.nextInt(upperX-lowerX + 1) + lowerX; // from 20 to 100
int y = r.nextInt(upperY-lowerY + 1) + lowerY; // from 50 to 100
int w = r.nextInt(maxWidth-minWidth + 1) + minWidth; // from 100 to 300
int h = r.nextInt(maxHeight - minHeight + 1) + minHeight; // from 50 to 200
return new Rectangle(x,y,w,h);
}
I wrote this program that is supposed to draw a Sierpinski triangle, however whenever I open it with appletviewer on a lower-end computer it will usually draw anywhere from 4 to 60 dots. If I re-open it without re-compiling it the number of dots will occasionally go up from the usual 4. Running it on my higher-end computer at home it works best at around 5 000 000 iterations. However, although it draws the shape fairly full, it starts to draw dots where it should not be possible for there to be dots. This only occurs when the numbers start to get higher. Why is my applet not working on lower end computers, and why does it draw pixels in the incorrect positions at greater values? Here is the code:
import java.applet.Applet;
import java.awt.*;
import java.util.Random;
public class Triangle extends Applet implements Runnable {
Thread runner;
Random rand = new Random();
int xCord, yCord;
double lastX, lastY, currentX, currentY;
final double topX = 500, topY = 100, leftX = 200, leftY = 700,
rightX = 800, rightY = 700;
public void start() {
if (runner == null)
{
runner = new Thread(this);
runner.start();
}
}
public void init() {
lastX = 500; //Top dot
lastY = 100;
}
public void run() {
for(int counter = 1; counter <= 5000000; counter++) {
int n = rand.nextInt(3) + 1;
if (n == 1) { //Top dot
currentX = topX + (lastX - topX) / 2;
currentY = topY + (lastY - topY) / 2;
lastX = currentX;
lastY = currentY;
xCord = (int)Math.round(currentX);
yCord = (int)Math.round(currentY);
repaint();
} else if (n == 2) { //Left dot
currentX = leftX + (lastX - leftX) / 2;
currentY = leftY + (lastY - leftY) / 2;
lastX = currentX;
lastY = currentY;
xCord = (int)Math.round(currentX);
yCord = (int)Math.round(currentY);
repaint();
} else { //Right dot
currentX = rightX + (lastX - rightX) / 2;
currentY = rightY + (lastY - rightY) / 2;
lastX = currentX;
lastY = currentY;
xCord = (int)Math.round(currentX);
yCord = (int)Math.round(currentY);
repaint();
}
}
}
public void update(Graphics g) {
paint(g);
}
public void paint(Graphics g) {
g.fillRect(500, 100, 2, 2); //Top dot, dot 1
g.fillRect(200, 700, 2, 2); //Bottom left dot, dot 2
g.fillRect(800, 700, 2, 2); //Bottom right dot, dot 3
g.fillRect(xCord, yCord, 2, 2);
}
}
Here is my HTML file:
<html>
<body>
<applet code = "Triangle.class" width=999 height=799>
</applet>
</body>
</html>
I'm building an application which has a slideshow in its homepage, currently I use Thread.sleep(10) and add/sub the x position of panel I want to slide.
For example: slideIn(30, panel_1, 10) < this will cause panel_1 to slide in with interval of 30ms and subtracts its x by 10 overtime until the panel is in center/occupy the slideshow_panel. But the con of this method is that the sliding animation won't smooth, I want the sliding animation/transition as smooth as Bootstrap Carousel. Is there a way to calculate the speed and increment/decrement value for slide transition speed?
Actually, I've something that's almost perfect for this. I assume you can create a Path2D for your animation path, right? And it also seems like you want a constant speed. There are a couple of references to my project (http://sourceforge.net/p/tus/code/HEAD/tree/) for calculating distance and showing the JPanel for instance, but it shouldn't be hard to remove them and replace with standard java. Try it out
public abstract class PathAnimation {
private Path2D mPath;
private double totalLength;
/**
* Be careful to call path.closePath before invoking this constructor
* #param path
*/
public PathAnimation(Path2D path) {
mPath = path;
totalLength = 0;
PathIterator iterator = mPath.getPathIterator(null);
//Point2D currentLocation;// = path.getCurrentPoint();
double[] location = new double[6];
iterator.currentSegment(location);
while (!iterator.isDone()) {
double[] loc = new double[6];
iterator.next();
iterator.currentSegment(loc);
if (loc[0] == 0 && loc[1] == 0) continue;
double distance = MathUtils.distance(location[0], location[1], loc[0], loc[1]);
totalLength += distance;
location = loc;
}
}
#Override
public Point2D getLocationAtTime(int time) {
return getLocationAtTime(time / (double) getTotalAnimationTime());
}
public Point2D getLocationAtTime(double pctTime) {
double len = totalLength * pctTime;
PathIterator iterator = mPath.getPathIterator(null);
double[] location = new double[6];
iterator.currentSegment(location);
while (!iterator.isDone()) {
double[] loc = new double[6];
iterator.next();
iterator.currentSegment(loc);
double distance= MathUtils.distance(location[0], location[1], loc[0], loc[1]);
if (distance > len) {
double pctThere = len / distance;
double xSpot = location[0] * (1 - pctThere) + loc[0] * pctThere;
double ySpot = location[1] * (1 - pctThere) + loc[1] * pctThere;
return new Point2D.Double(xSpot, ySpot);
}
len -= distance;
location = loc;
}
throw new ArrayIndexOutOfBoundsException("Path is too short or time is too long!");
}
/**
* Number of milliseconds that this animation spans
* #return
*/
public abstract int getTotalAnimationTime();
public static void main(String args[]) {
Rectangle rect = new Rectangle(10,10,20,20);
final Path2D.Double myPath = new Path2D.Double((Shape)rect);
myPath.closePath();
final PathAnimation myAnimation = new PathAnimation(myPath) {
Area star = new Area(PaintUtils.createStandardStar(15, 15, 5, .5, 0));
#Override
public Dimension getSizeAtTime(int time) {
return new Dimension(15,15);
}
#Override
public void paintAtTime(Graphics2D g, int time) {
Area toPaint = star;
if ((time / 150) % 2 == 1) {
Dimension size = getSizeAtTime(0);
toPaint = new Area(toPaint);
PaintUtils.rotateArea(toPaint, Math.PI / 6);
}
g.setColor(Color.YELLOW);
g.fill(toPaint);
g.setColor(Color.RED);
g.draw(toPaint);
}
#Override
public int getTotalAnimationTime() {
return 10000;
}
};
System.out.println(myAnimation.getLocationAtTime(0));
System.out.println(myAnimation.getLocationAtTime(2500));
System.out.println(myAnimation.getLocationAtTime(4000));
System.out.println(myAnimation.getLocationAtTime(5000));
System.out.println(myAnimation.getLocationAtTime(7000));
System.out.println(myAnimation.getLocationAtTime(7500));
System.out.println(myAnimation.getLocationAtTime(9000));
System.out.println(myAnimation.getLocationAtTime(10000));
final JPanel jp = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int time = ((int) System.currentTimeMillis()) % myAnimation.getTotalAnimationTime();
int time2 = (time + myAnimation.getTotalAnimationTime() / 2) % myAnimation.getTotalAnimationTime();
Point2D pt = myAnimation.getLocationAtTime(time);
Point2D pt2 = myAnimation.getLocationAtTime(time2);
Dimension size = myAnimation.getSizeAtTime(time);
g2.translate(pt.getX() - size.width / 2, pt.getY() - size.height / 2);
myAnimation.paintAtTime(g2, time);
g2.translate(- (pt.getX() - size.width / 2), - (pt.getY() - size.height / 2));
g2.translate(pt2.getX() - size.width / 2, pt2.getY() - size.height / 2);
myAnimation.paintAtTime(g2, time2);
g2.translate(- (pt2.getX() - size.width / 2), - (pt2.getY() - size.height / 2));
g2.setColor(Color.BLACK);
g2.draw(myPath);
}
};
WindowUtilities.visualize(jp);
AbstractAction action = new AbstractAction() {
public void actionPerformed(ActionEvent ae) {
jp.repaint();
}
};
javax.swing.Timer t = new javax.swing.Timer(30, action);
t.start();
}
}
I've been trying to make a 2D Tile-based game but didnt get very far before having some stuff go wrong. The game is fine except for that it is extremely slow and spaces keep appearing between the tiles. I tried putting all of the tile images into one image to load to make it smoother, but it didn't work. I need help with how to optimize my game for better fps.
Most of Display Class
Player p = new Player();
static Map m = new Map();
Hotbar h = new Hotbar();
static Zombie z = new Zombie();
public static void main(String args[]) {
Thread t1 = new Thread(new Display());
t1.start();
Thread t2 = new Thread(z);
t2.start();
Thread t3 = new Thread(m);
t3.start();
}
#SuppressWarnings("static-access")
public void run() {
while (true) {
try {
oldTime = currentTime;
currentTime = System.currentTimeMillis();
elapsedTime = currentTime - oldTime;
fps = (int) ((1000 / 40) - elapsedTime);
Thread.sleep(fps);
} catch (Exception e) {
e.printStackTrace();
}
if (started) {
p.playerMovement();
p.width = getWidth();
p.height = getHeight();
h.width = getWidth();
h.height = getHeight();
if (p.maptiles != null) {
z.maptiles = new Rectangle[p.maptiles.length];
z.maptiles = p.maptiles;
}
} else {
}
repaint();
}
}
Most of Map Class
BufferedImage backLayer;
BufferedImage backLayer2;
#SuppressWarnings("static-access")
public void createBack() {
backLayer = new BufferedImage(mapwidth * 32, mapheight * 32, BufferedImage.TYPE_INT_ARGB);
Graphics g = backLayer.getGraphics();
Graphics2D gd = (Graphics2D) g;
Color daycolor = new Color(0, 150, 255, 255);
Color nightcolor = new Color(0, 50, 100, Math.abs(time / daylength - 510 / 2));
Color backtilecolor = new Color(10, 10, 20, Math.abs(time / daylength - 510 / 4));
g.setColor(daycolor);
g.fillRect(0, 0, p.width, p.height);
g.setColor(nightcolor);
g.fillRect(0, 0, p.width, p.height);
time++;
if (time > 510 * daylength)
time = 0;
if (time < 100 * daylength || time > 410 * daylength) {
z.SpawnZombie();
} else {
}
g.setColor(backtilecolor);
int i = 0;
for (int x = 0; x < mapwidth; x++) {
for (int y = 0; y < mapheight; y++) {
if (mapdatasky[i] == 0) {
p.mapsky[i] = new Rectangle(x * 32 - p.playerX, y * 32 - p.playerY, 32, 32);
}
if (mapdatasky[i] >= 1) {
g.drawImage(tiles[mapdatasky[i]], x * 32 - p.playerX, y * 32 - p.playerY, 32, 32, null);
mapsky[i] = new Rectangle(x * 32 - p.playerX, y * 32 - p.playerY, 32, 32);
p.mapsky[i] = new Rectangle(x * 32 - p.playerX, y * 32 - p.playerY, 32, 32);
gd.fill(mapsky[i]);
}
i++;
}
}
backLayer2 = backLayer;
}
BufferedImage middleLayer;
BufferedImage middleLayer2;
#SuppressWarnings("static-access")
public void createMiddle() {
middleLayer = new BufferedImage(mapwidth * 32, mapheight * 32, BufferedImage.TYPE_INT_ARGB);
Graphics g = middleLayer.getGraphics();
Color fronttilecolor = new Color(20, 20, 40, Math.abs(time / daylength - 510 / 4));
int i = 0;
for (int x = 0; x < mapwidth; x++) {
for (int y = 0; y < mapheight; y++) {
if (mapdata[i] == -1) {
spawnX = x * 32 - p.width;
spawnY = y * 32 - p.height;
p.spawnX = spawnX;
p.spawnY = spawnY;
}
if (mapdata[i] == 0) {
p.mapsky[i] = new Rectangle(x * 32 - p.playerX, y * 32 - p.playerY, 32, 32);
}
if (mapdata[i] > 0) {
g.drawImage(tiles[mapdata[i]], x * 32 - p.playerX, y * 32 - p.playerY, 32, 32, null);
maptiles[i] = new Rectangle(x * 32 - p.playerX, y * 32 - p.playerY, 32, 32);
p.maptiles[i] = new Rectangle(x * 32 - p.playerX, y * 32 - p.playerY, 32, 32);
}
if (!p.breaking) {
tileid = -1;
}
if (tileid == i) {
g.setColor(new Color(100, 0, 0, 100));
g.fillRect(x * 32 - p.playerX + 16 - timer / (breaktime / 16), y * 32 - p.playerY + 16 - timer / (breaktime / 16), (timer / (breaktime / 16)) * 2, (timer / (breaktime / 16)) * 2);
}
i++;
}
}
g.setColor(fronttilecolor);
g.fillRect(0, 0, p.width, p.height);
middleLayer2 = middleLayer;
}
BufferedImage both;
BufferedImage both2;
public void mergeLayers() {
both = new BufferedImage(mapwidth * 32, mapheight * 32, BufferedImage.TYPE_INT_ARGB);
Graphics g = both.getGraphics();
g.drawImage(backLayer2, 0, 0, mapwidth * 32, mapheight * 32, null);
g.drawImage(middleLayer2, 0, 0, mapwidth * 32, mapheight * 32, null);
both2 = both;
}
public void renderMap(Graphics g) {
g.drawImage(both2, 0, 0, mapwidth * 32, mapheight * 32, null);
if (placetimer > 0)
placetimer--;
}
#Override
public void run() {
while (true) {
try {
oldTime = currentTime;
currentTime = System.currentTimeMillis();
elapsedTime = currentTime - oldTime;
fps = (int) ((1000 / 100) - elapsedTime);
Thread.sleep(fps);
if (!mapset) {
setMap();
mapset = true;
}
createBack();
createMiddle();
mergeLayers();
} catch(Exception e) {
e.printStackTrace();
}
}
}
Here is a picture of the rendering errors between tiles
Game Screenshot:
I agree that a review might be appropriate here.
But general hints: If you added this "merging" (createBack/createMiddle/mergeLayers) for performance reasons: Don't do it! There you are painting ALL tiles (and possibly also some that will not be visible anyhow, that could be clipped away when they are drawn directly with g.drawImage). Painting many small images into a large image, and then painting the large image on the screen, can hardly be faster than directly painting the small images on the screen in the first place....
If you added this "merging" to resolve the "stripes" that are appearing: Don't do it! The stripes come from the coordinates being changed from a different Thread than the one which is painting the images. You can avoid this by changing the way of how you compute the tiles and their coordinates. The code is slightly too ... "complex" to point it out, so I'll use some pseudocode here:
void paintTiles(Graphics g)
{
for (Tile tile : allTiles)
{
g.drawImage(tile, player.x, player.y, null);
}
}
The problem here is that while the painting thread is iterating over all tiles, the other thread may change the player coordinates. For example, some tiles may be painted with player.x=10 and player.y=20, then the other thread changes the player coordinates, and thus the remaining tiles are painted with player.x=15 and player.y=25 - and you'll notice this as a "stripe" appearing between the tiles.
In the best case, this can be resolved rather easily:
void paintTiles(Graphics g)
{
int currentPlayerX = player.x;
int currentPlayerY = player.y;
for (Tile tile : allTiles)
{
g.drawImage(tile, currentPlayerX, currentPlayerY, null);
}
}
This way, the "current" player coordinates will remain the same while iterating over the tiles.
In connection with question Resizing a component without repainting is my question how to create resiziable custom Graphics2d in form
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ZoomWithSelectionInViewport implements MouseWheelListener {
private JComponent b;
private int hexSize = 3;
private int zoom = 80;
private JScrollPane view;
public ZoomWithSelectionInViewport() throws Exception {
b = new JComponent() {
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
return new Dimension(700, 700);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = ((Graphics2D) g);
int vertOffsetX, vertOffsetY, horizOffsetX, horizOffsetY;
vertOffsetX = (int) ((double) hexSize * Math.sqrt(3.0f));
vertOffsetY = (int) ((double) -hexSize - 1 * Math.sqrt(3.0f) / 2.0f);
horizOffsetX = (int) ((double) hexSize * Math.sqrt(3.0f));
horizOffsetY = (int) ((double) hexSize + 1 * Math.sqrt(3.0f) / 2.0f);
for (int x = 0; x < 50; x++) {
for (int y = 0; y < 50; y++) {
int[] xcoords = new int[6];
int[] ycoords = new int[6];
for (int i = 0; i < 6; i++) {
xcoords[i] = (int) ((hexSize + x * horizOffsetX + y * vertOffsetX)
+ (double) hexSize * Math.cos(i * 2 * Math.PI / 6));
ycoords[i] = (int) (((getSize().height / 2) + x * horizOffsetY
+ y * vertOffsetY) + (double) hexSize * Math.sin(i * 2 * Math.PI / 6));
}
g2d.setStroke(new BasicStroke(hexSize / 2.5f));
g2d.setColor(Color.GRAY);
g2d.drawPolygon(xcoords, ycoords, 6);
}
}
}
};
view = new JScrollPane(b);
b.addMouseWheelListener(this);
JFrame f = new JFrame();
f.setLocation(10, 10);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(view);
f.setPreferredSize(b.getPreferredSize());
f.pack();
f.setVisible(true);
}
public void mouseWheelMoved(MouseWheelEvent e) {
zoom = 100 * -Integer.signum(e.getWheelRotation());
if (hexSize - Integer.signum(e.getWheelRotation()) > 0) {
hexSize -= Integer.signum(e.getWheelRotation());
}
Dimension targetSize = new Dimension(b.getWidth() + zoom, b.getHeight() + zoom);
b.setPreferredSize(targetSize);
b.setSize(targetSize);
b.revalidate();
b.repaint();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
ZoomWithSelectionInViewport example = new ZoomWithSelectionInViewport();
} catch (Exception ex) {
//
}
}
});
}
}
If I understand correctly, you want the scroll pane's scroll bars to reflect the current zoom state. I see two alternatives:
Don't override getPreferredSize() in the component, and adjust the preferred size in the mouse listener to include the zoomed image; it appears slightly truncated on the right.
Do override getPreferredSize() in the component, and adjust the returned Dimension (now a constant) to include the zoomed boundary implicit in paintComponent().
I'd prefer the latter. I've also found it helpful to write explicit transformation functions to convert zoomed and un-zoomed coordinates, as shown here. An inverse AffineTransform, shown here, is also possible.