Checkerboard not drawing correct amount of checkers - java

I am trying to develop a checkerboard given a template of classes and some code for school. I got the board to appear but the right amount of checkers are not being drawn. There are supposed to be 7 red and 9 black checkers but each time I run the program a different amount of each is drawn.
import java.applet.Applet;
import java.awt.*;
import java.util.Random;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class Checkers extends JApplet
{
private final int MAX_SIZE = 8;
private final int APP_WIDTH = 400;
private final int APP_HEIGHT = 400;
private final int MAXSIZE = 8;
Square[][] sq;
public void paint(Graphics page)
{
setBackground(Color.white);
fillBoard(page); // draws the method that will draw the checkers
placeCheckers(page, 7, Color.red); //method to place the red checkers
placeCheckers(page, 9, Color.black); //method to draw black checkers
CheckJumps(page); //check if checkers can jump
setSize (APP_WIDTH,APP_HEIGHT);
}
public void fillBoard(Graphics page)
{
sq = new Square[8][8];
int x,y;
Color rb;
for (int row = 0; row < MAXSIZE; row++)
for (int col = 0; col < MAXSIZE; col++)
{
x = row * (APP_WIDTH/MAXSIZE);
y = col * (APP_HEIGHT/MAXSIZE);
if ( (row % 2) == (col % 2) )
rb = Color.red;
else
rb = Color.black;
sq[row][col] = new Square (x, y, rb);
}
for (int row = 0; row < 8; row++)
for (int col = 0; col < 8; col++)
sq[row][col].draw(page);
}
public void placeCheckers (Graphics page, int num_checkers, Color ncolor)
{
int count, row, col;
int x, y;
Circle c;
Random rand = new Random();
for (count = 0; count < num_checkers; count++)
{
do
{
row = rand.nextInt(8);
col = rand.nextInt(8);
} while (sq[row][col].getOccupy() || ncolor == sq[row][col].getColor());
x = row * (APP_WIDTH/MAXSIZE);
y = col * (APP_HEIGHT/MAXSIZE);
c = new Circle (x, y, 50, ncolor);
c.draw(page);
sq[row][col].setOccupy(true);
}
}
class Square
{
private int x, y = 0;
private Color c;
private boolean occupied;
public Square (int x, int y, Color c)
{
this.x = x;
this.y = y;
this.c = c;
}
public void setX (int x)
{
x = this.x;
}
public int getX ()
{
return x;
}
public void setY (int y)
{
y= this.y;
}
public int getY ()
{
return y;
}
public void setColor (Color c)
{
c = this.c;
}
public Color getColor ()
{
return c;
}
public void setOccupy (boolean occupied)
{
occupied = this.occupied;
}
public boolean getOccupy ()
{
return occupied;
}
public String toString()
{
return ("X coordinate: " + x + "\nY coordinate:" + y + "\nSquare color: " + c);
}
public void draw (Graphics page)
{
page.setColor(c);
page.fillRect(x, y, 50, 50);
}
}
class Circle
{
private int x,y;
private int diameter;
private Color c;
public Circle (int x, int y, int diameter, Color c)
{
this.x = x;
this.y = y;
this.diameter = diameter;
this.c = c;
}
public void setX (int x)
{
x = this.x;
}
public int getX ()
{
return x;
}
public void setY (int y)
{
y= this.y;
}
public int getY ()
{
return y;
}
public void setColor (Color c)
{
c = this.c;
}
public Color getColor ()
{
return c;
}
public void setDiameter (int x)
{
diameter = x;
}
public void draw (Graphics page)
{
page.setColor(c);
page.fillOval(x, y, diameter, diameter);
}
}

If, you have followed some of the advice from your previous question you may have avoided this issue.
As near as I can tell, your problem is you're not calling super.paint, which is responsible for (amongst a lot of other things) preparing the Graphics context for painting. It does this, by clearing what ever was painted on it previously.
Instead of overriding paint of JApplet, which will cause flicker when the applet is updated, you should start with something like a JPanel and override it's paintComponent method. JPanel is double buffered, which will prevent any flicker from occuring. Don't forget to call super.paintComponent.
You shouldn't be calling fillBorder every time paint is called, this is wasteful on a number of levels, instead, you should only call it when you need to. With a little bit more clever design, you could actually get away with calling it from the constructor, but I don't have the time to re-code your entire program.
The size the applet is defined by the HTML page which contains it, not the applet itself, relying on magic numbers (like APP_WIDTH and APP_HEIGHT) is a bad idea. You should, instead, rely on known values, like getWidth and getHeight. This of course assumes you'd like to be able to resize the playable area and avoid possible issues with people deploying your applet with the wrong size ;)
While, I'm guessing that placeCheckers is a test method, you should know, paint can be called any number of times for any number of reasons, many of which you don't control, this means that the checkers will be randomized each time paint is called.
Instead, you should consider creating a virtual board which contains the information about the state of the game and update this as required. You would then simply use the painting process to reflect this model.
An example of how I might "start"...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JApplet;
import javax.swing.JPanel;
public class Checkers extends JApplet {
#Override
public void init() {
add(new Board());
}
public class Board extends JPanel {
private final int APP_WIDTH = 400;
private final int APP_HEIGHT = 400;
private final int MAXSIZE = 8;
Square[][] sq;
#Override
public void invalidate() {
fillBoard();
super.invalidate();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
sq[row][col].draw(g);
}
}
setBackground(Color.white);
placeCheckers(g, 7, Color.red); //method to place the red checkers
placeCheckers(g, 9, Color.black); //method to draw black checkers
}
#Override
public Dimension getPreferredSize() {
return new Dimension(APP_WIDTH, APP_HEIGHT);
}
public void fillBoard() {
sq = new Square[8][8];
int x, y;
Color rb;
int gridSize = Math.min(getWidth(), getHeight());
int size = gridSize / MAXSIZE;
for (int row = 0; row < MAXSIZE; row++) {
for (int col = 0; col < MAXSIZE; col++) {
x = row * (gridSize / MAXSIZE);
y = col * (gridSize / MAXSIZE);
if ((row % 2) == (col % 2)) {
rb = Color.red;
} else {
rb = Color.black;
}
sq[row][col] = new Square(x, y, rb, size);
}
}
}
public void placeCheckers(Graphics page, int num_checkers, Color ncolor) {
int count, row, col;
int x, y;
Circle c;
int gridSize = Math.min(getWidth(), getHeight());
int size = gridSize / MAXSIZE;
Random rand = new Random();
for (count = 0; count < num_checkers; count++) {
do {
row = rand.nextInt(8);
col = rand.nextInt(8);
} while (sq[row][col].getOccupy() || ncolor == sq[row][col].getColor());
x = row * (gridSize / MAXSIZE);
y = col * (gridSize / MAXSIZE);
c = new Circle(x, y, size, ncolor);
c.draw(page);
sq[row][col].setOccupy(true);
}
}
}
class Square {
private int x, y = 0;
private Color c;
private boolean occupied;
private int size;
public Square(int x, int y, Color c, int size) {
this.x = x;
this.y = y;
this.c = c;
this.size = size;
}
public void setX(int x) {
x = this.x;
}
public int getX() {
return x;
}
public void setY(int y) {
y = this.y;
}
public int getY() {
return y;
}
public void setColor(Color c) {
c = this.c;
}
public Color getColor() {
return c;
}
public void setOccupy(boolean occupied) {
occupied = this.occupied;
}
public boolean getOccupy() {
return occupied;
}
public String toString() {
return ("X coordinate: " + x + "\nY coordinate:" + y + "\nSquare color: " + c);
}
public void draw(Graphics page) {
page.setColor(c);
page.fillRect(x, y, size, size);
}
}
class Circle {
private int x, y;
private int diameter;
private Color c;
public Circle(int x, int y, int diameter, Color c) {
this.x = x;
this.y = y;
this.diameter = diameter;
this.c = c;
}
public void setX(int x) {
x = this.x;
}
public int getX() {
return x;
}
public void setY(int y) {
y = this.y;
}
public int getY() {
return y;
}
public void setColor(Color c) {
c = this.c;
}
public Color getColor() {
return c;
}
public void setDiameter(int x) {
diameter = x;
}
public void draw(Graphics page) {
page.setColor(c);
page.fillOval(x, y, diameter, diameter);
}
}
}
Updated
This ones had me scratching me head for a while. Basically, after some additional checking I discovered that the checkers where being allowed to occupy space that was suppose to be already taken. After bashing me head against the do-while loop, I check the setOccupy method and found...
public void setOccupy(boolean occupied) {
occupied = this.occupied;
}
You're assiging the Square's occupied state back to the value you are passing, which has no effect on anything
Instead, it should look more like...
public void setOccupy(boolean occupied) {
this.occupied = occupied;
}
You may also like to have a read through Why CS teachers should stop teaching Java applets

Related

Character can not move any more

So here is the code after taking the tips into account.
The map is kept being repainted, the keylistener has changed but there still seems to be a problem.
The problem again is, the little square in the upper left corner will not move, which is the desired outcome.
package schoolgamev2;
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Spel {
public static void main(String[] args) {
Speelveld map = new Speelveld();
map.Speelveld();
map.GenerateMap();
}
}
class Speelveld extends JPanel {
final int rijen = 16;
final int kolommen = 16;
Speler speler = new Speler();
Loopgebied loopgebied = new Loopgebied();
Blokken blok = new Blokken();
int[][] coordinaten = new int[rijen][kolommen];
public void Speelveld() {
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(this);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
setFocusable(true);
addKeyListener(new KeyListener(this));
}
//genereer map
public void GenerateMap() {
Random random = new Random();
int x;
int y;
for (y = 0; y < rijen; y++) { //scan langs y
for (x = 0; x < kolommen; x++) { //scan langs x
//selecteert type blok voor coordinaten x y
coordinaten[x][y] = random.nextInt(4);
//debugprint
}
//debugprint
}
coordinaten[0][0] = 4; //speler begint altijd links boven
coordinaten[15][15] = 5; //finish is altijd rechts onder
}
public int[][] getCoordinaten() {
return coordinaten;
}
public Speler getSpeler2() {
return speler;
}
public int getSpelerX() {
return speler.getX();
}
public int getSpelerY() {
return speler.getY();
}
public void setSpelerX(int x) {
speler.setX(x);
}
public void setSpelerY(int y) {
speler.setY(y);
}
//#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int x;
int y;
for (y = 0; y < rijen; y++) { //scan langs y
System.out.println("");
for (x = 0; x < kolommen; x++) { //scan langs x
blok.setX(x);
blok.setY(y);
blok.setType(coordinaten[x][y]);
System.out.print(coordinaten[x][y] + " ");
switch (blok.getType()) {
case 0:
loopgebied.teken(g);
break;
case 4:
speler.teken(g);
/*case 5:
eindveld.teken(g);
break;*/
default:
break;
}
}
}
}
}
class Speler extends Blokken {
Blokken blok = new Blokken();
public void teken(Graphics g) {
g.drawRect(blok.getX(), blok.getY(), 10, 10);
}
}
class Loopgebied extends Blokken {
Blokken blok = new Blokken();
public void teken(Graphics g) {
g.drawRect(blok.getX() * size, blok.getY() * size, size, size);
}
}
class Blokken {
private static int x;
private static int y;
private static int type;
public int size = 16;
//setters voor x y en type
public void setX(int xIn) {
x = xIn;
}
public void setY(int yIn) {
y = yIn;
}
public void setType(int typeIn) {
type = typeIn;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getType() {
return type;
}
}
class KeyListener extends KeyAdapter {
private static final int SCALE = 3;
private Speelveld speelveld;
public KeyListener(Speelveld speelveld) {
this.speelveld = speelveld;
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
int deltaX = 0;
int deltaY = 0;
if (key == KeyEvent.VK_LEFT) {
deltaX = -1 * SCALE;
deltaY = 0;
} else if (key == KeyEvent.VK_UP) {
deltaX = 0;
deltaY = -1 * SCALE;
} else if (key == KeyEvent.VK_RIGHT) {
deltaX = 1 * SCALE;
deltaY = 0;
} else if (key == KeyEvent.VK_DOWN) {
deltaX = 0;
deltaY = 1 * SCALE;
} else {
return;
}
int x = speelveld.getSpelerX() + deltaX;
int y = speelveld.getSpelerY() + deltaY;
speelveld.setSpelerX(x);
speelveld.setSpelerY(y);
speelveld.repaint();
}
}
As mentioned in comments, you got your player, the Speler class, that extends JPanel and is wired to use a KeyListener, but note that it is not being used as a JPanel, and so the KeyListener is non-functioning, because they only work when they have been added to a visible component that has focus.
Suggestions:
Again as per comments, make Speler a non-GUI logical class. Meaning don't have it extend JPanel or any other Swing component, and certainly don't add a KeyListener to it.
Instead give it code for the player's behavior and for having the player draw itself, and that's it. What I'm suggesting is that you try to separate part of your "Model" here the player from the "View" here the Swing GUI.
Have one JPanel and only one that does drawing. Have it override paintComponent (don't forget to call the super's paintComponent within it), and have it draw each logical component by calling the logical component's draw method (public void verf(Graphics2D g2)? or public void teken(Graphics2D g2)?) within its paintComponent method.
As a general rule, you also don't want your GUI component classes, the JPanel here, directly implementing listener interfaces, such as the KeyListener, but will want to keep them separate.
Either make this drawing JPanel focusable, give it focus and add the KeyListener, a separate class, to it.
Or better, use Key Bindings as per the tutorial: Key Bindings
For example the simple [MCVE] below doesn't use a Swing Timer or change velocities, but rather it uses a KeyListener to change position of the Speler2 object using only one drawing JPanel and a KeyListener. If I were making this more robust and larger, I would use the Swing Timer, would use Key Bindings, and would change the velocities using the key bindings.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class Spel2 {
private static final int VELD_WIDTH = 500;
private static void createAndShowGui() {
Speelveld2 speelveld2 = new Speelveld2(VELD_WIDTH, VELD_WIDTH);
JFrame frame = new JFrame("Spel2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(speelveld2);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
speelveld2.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class MyKeyListener extends KeyAdapter {
private static final int SCALE = 3;
private Speelveld2 speelveld2;
public MyKeyListener(Speelveld2 speelveld2) {
this.speelveld2 = speelveld2;
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
int deltaX = 0;
int deltaY = 0;
if (key == KeyEvent.VK_LEFT) {
deltaX = -1 * SCALE;
deltaY = 0;
} else if (key == KeyEvent.VK_UP) {
deltaX = 0;
deltaY = -1 * SCALE;
} else if (key == KeyEvent.VK_RIGHT) {
deltaX = 1 * SCALE;
deltaY = 0;
} else if (key == KeyEvent.VK_DOWN) {
deltaX = 0;
deltaY = 1 * SCALE;
} else {
return;
}
int x = speelveld2.getSpelerX() + deltaX;
int y = speelveld2.getSpelerY() + deltaY;
speelveld2.setSpelerX(x);
speelveld2.setSpelerY(y);
speelveld2.repaint();
}
}
#SuppressWarnings("serial")
class Speelveld2 extends JPanel {
private int prefW;
private int prefH;
private Speler2 speler2 = new Speler2();
public Speelveld2(int prefW, int prefH) {
this.prefW = prefW;
this.prefH = prefH;
setFocusable(true);
addKeyListener(new MyKeyListener(this));
}
public Speler2 getSpeler2() {
return speler2;
}
public int getSpelerX() {
return speler2.getX();
}
public int getSpelerY() {
return speler2.getY();
}
public void setSpelerX(int x) {
speler2.setX(x);
}
public void setSpelerY(int y) {
speler2.setY(y);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
speler2.teken(g2);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
}
class Speler2 extends Blokken2 {
private static final int RECT_W = 10;
public Speler2() {
super(BlokkenType.SPELER);
}
#Override
public void teken(Graphics2D g2) {
int x = getX();
int y = getY();
g2.drawRect(x, y, RECT_W, RECT_W);
}
}
class Blokken2 {
private int x;
private int y;
private int velx = 0;
private int vely = 0;
private BlokkenType type;
private BufferedImage img;
public Blokken2(BlokkenType type) {
this.type = type;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getVelx() {
return velx;
}
public void setVelx(int velx) {
this.velx = velx;
}
public int getVely() {
return vely;
}
public void setVely(int vely) {
this.vely = vely;
}
public BlokkenType getType() {
return type;
}
public void setType(BlokkenType type) {
this.type = type;
}
public void setImg(BufferedImage img) {
this.img = img;
}
public BufferedImage getImg() {
return img;
}
public void teken(Graphics2D g2) {
if (img != null) {
g2.drawImage(img, x, y, null);
}
}
}
enum BlokkenType {
LOOPGEBIED, BARRICADE, MUUR, SLEUTEN, SPELER, EINDVELD
}
Edit: your latest code has an error here:
class Speler extends Blokken {
Blokken blok = new Blokken();
public void teken(Graphics g) {
g.drawRect(blok.getX(), blok.getY(), 10, 10);
}
}
Regarding your edit:
Now when you create a Speler instance, you create TWO Blokken instances, one which is the Speler instance since it extends Blokken and the other which is contained by the Speler instance since it also has a Blokken field.
You update the x/y state of the first one, but you draw with the second one, and that's why no motion is being displayed. The solution is obvious: use one or the other but not both. Either have Speler extend Blokken or have it contain a Blokken instance but don't do both.

How can I make each block move in the opposite direction once they reach a certain point on the side of the screen?

I am trying to get three different blocks to move back and forth from one side of the screen to the other. If the block on the far right reaches the game frame's width, it's velocity is reversed and it starts moving to the left side. However, my problem exists with the other two blocks. I put in my code a method that states once the second block reaches the (game width - 100), with 100 just being the width of each blocks, it's velocity should be reversed. The third block is suppose to work the same except once it reaches the x point (game width - 200). My attempt to change the velocity of the second and third blocks can be seen under the UpdateBlocks method in the PlayState class posted below.
Another thing I want to point out is that in update method in the block class, the x value is being reversed too. I tried at first to make it read the blocks from the PlayState then change the corresponding velocities but I got a thread error. That's why I am bringing my current predicament to you.
Here is the block class:
package com.jamescho.game.model;
import java.awt.Rectangle;
import com.jamescho.framework.util.RandomNumberGenerator;
import com.jamescho.game.main.GameMain;
import com.jamescho.game.state.PlayState;
public class Block {
private float x, y;
private int width, height, velX = 700;
private Rectangle rect;
private PlayState play;
private boolean visible;
private static final int UPPER_Y = 275;
private static final int LOWER_Y = 355;
public Block(float x, float y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
rect = new Rectangle((int) x, (int) y, width, height);
visible = false;
}
// Note: Velocity value will be passed in from PlayState!
public void update(float delta) {
x += velX * delta;
if (x <= 0 || x >= GameMain.GAME_WIDTH - 100) {
velX = -velX;
}
updateRect();
}
public void updateRect() {
rect.setBounds((int) x, (int) y, width, height);
}
public void invisible() {
visible = false;
}
public void visible() {
visible = true;
}
public void stop() {
velX = 0;
}
public void reverse() {
velX = -velX;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public boolean isVisible() {
return visible;
}
public Rectangle getRect() {
return rect;
}
}
Here is the PlayState where everything is going on:
package com.jamescho.game.state;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import com.jamescho.game.main.GameMain;
import com.jamescho.game.main.Resources;
import com.jamescho.game.model.Block;
public class PlayState extends State {
private ArrayList<Block> row1;
private ArrayList<Block> row2;
private ArrayList<Block> row3;
private Block block;
private Font scoreFont;
private int playerScore = 0;
private static final int BLOCK_HEIGHT = 100;
private static final int BLOCK_WIDTH = 100;
private int blockSpeed = -200;
private static final int PLAYER_WIDTH = 66;
private static final int PLAYER_HEIGHT = 92;
#Override
public void init() {
row1 = new ArrayList<Block>();
row2 = new ArrayList<Block>();
scoreFont = new Font("SansSerif", Font.BOLD, 25);
for (int i = 0; i < 3; i++) {
Block b = new Block(i * 105, GameMain.GAME_HEIGHT - 101,
BLOCK_WIDTH, BLOCK_HEIGHT);
row1.add(b);
b.visible();
for (int h = 0; h < 3; h++) {
Block b2 = new Block(h * 105, b.getY() - 208,
BLOCK_WIDTH, BLOCK_HEIGHT);
row2.add(b2);
b2.invisible();
}
}
}
#Override
public void update(float delta) {
playerScore += 1;
if (playerScore % 500 == 0 && blockSpeed > -280) {
blockSpeed -= 10;
}
Resources.runAnim.update(delta);// starts iterating through its frames
updateBlocks(delta);
}
private void updateBlocks(float delta) { // time from last update
for (Block b : row1) { //foreach statement; for each iteration of "b" the code is executed, one "b" at a time
if(row1.get(1).getX() == GameMain.GAME_WIDTH - BLOCK_WIDTH - 5) {
row1.get(1).reverse();
}
else if(row1.get(2).getX() == GameMain.GAME_WIDTH - 2 * BLOCK_WIDTH - 5) {
row1.get(2).reverse();
}
b.update(delta);
}
for (Block c : row2) { //foreach statement; for each iteration of "b" the code is executed, one "b" at a time
// used with objects; can't use primitive
c.update(delta);
if (c.isVisible()) {
}
}
}
#Override
public void render(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, GameMain.GAME_WIDTH, GameMain.GAME_HEIGHT);
renderPlayer(g);
renderBlocks(g);
renderScore(g);
}
private void renderScore(Graphics g) {
g.setFont(scoreFont);
g.setColor(Color.GRAY);
g.drawString("" + playerScore / 100, 20, 30);
}
private void renderPlayer(Graphics g) {
}
private void renderBlocks(Graphics g) {
for (Block b : row1) {
if (b.isVisible()) {
g.drawImage(Resources.blue_panel, (int) b.getX(), (int) b.getY(),
BLOCK_WIDTH, BLOCK_HEIGHT, null); // change null if you want the object to know about object
}
}
for (Block c : row2) {
if (c.isVisible()) {
g.drawImage(Resources.blue_panel, (int) c.getX(), (int) c.getY()+105,
BLOCK_WIDTH, BLOCK_HEIGHT, null); // change null if you want the object to know about object
}
}
}
#Override
public void onClick(MouseEvent e) {
}
#Override
public void onKeyPress(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
for (Block b : row1) {
b.stop();
for (Block c : row2) {
if (c.isVisible() == true) {
c.stop();
}
}
}
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
}
}
#Override
public void onKeyRelease(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE) {
for (Block c: row2) {
c.visible();
}
}
}
public float getb1X() {
return row1.get(1).getX();
}
}
Sorry I haven't gone through your entire code. But this is how I would do it:
int x , int y -- are the coordinates of each block on the screen.
a block can move on the screen in 4 ways / directions / quadrants:
1) x = x + deltaX, y = y + deltaY
2) x = x - deltaX, y = y + deltaY
3) x = x + deltaX, y = y - deltaY
4) x = x - deltaX, y = y - deltaY
Thus in order to change the direction when a block hits any side you should multiply deltaX with -1 if it hits left or right side and deltaY with -1 if it hits the bottom or top. this will reverse its direction.

How to randomly generate tiles in java code

I have question about random generation of sprite sheet tiles in java. Whenever I try to use a for loop the random generation changes every millisecond or faster. I am very confused and have no idea where to start from here. If anyone can come up with some easy code for a begginer to grasp the concept of random generation!
Here is the code I am working with for generating a flat map /
public class Map {
Random random = new Random();
public static int mapxDirection;
public static int mapx = 1;
public static int bgSpeed = 20;
public static int grass = 16;
public static int dirt = 0;
public static int stone = 1;
public static int waterup = 2;
public static int waterside = 18;
public static int glass = 17;
public static int chicken = 32;
public static int steak = 33;
public static int mapSpeed = 3;
public static BufferedImage[] sprites;
public void renderMap(Graphics g) {
final int width = 32;
final int height = 32;
final int rows = 16;
final int cols = 16;
sprites = new BufferedImage[rows * cols];
BufferedImage spritesheet = null;
try {
spritesheet = ImageIO.read(new File("res/SpriteSheet.png"));
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
sprites[(i * cols) + j] = spritesheet.getSubimage(i * width, j
* height, width, height);
}
}
for (int i = 0; i < 2000; i += 32) {
g.drawImage(sprites[grass], Map.mapx + i, 259, null);
}
for (int i = 0; i < 2000; i += 32) {
for (int j = 291; j <= 508; j += 32) {
g.drawImage(sprites[dirt], Map.mapx + i, j, null);
}
}
for (int i = 0; i < 2000; i += 32) {
for (int j = 508; j <= 540; j += 32) {
g.drawImage(sprites[stone], Map.mapx + i, j - 3, null);
}
}
}
}
There are multiple ways this can be done, it also depends on what type on random generation you want to achieve for example, do you what to completely randomize every tile or do you what to load random chunks. The popular game Minecraft uses the method of random chuck generation.
If your new to game programming, i recommend checking out RealTutsGML Game Programming Tutorials. He teaches you a easy and good way of loading in sprite sheets and also teaches you how to load in and create a level in paint. All though he is making a platformer, you can easily convert the same method into a top down game.
Here is how i would go about creating a random generation map. First i would create a abstract class called GameObject. Every object you make will extend this class.
public abstract class GameObject {
protected float x, y;
protected ObjectId id;
protected float velX= 0, velY = 0;
protected boolean falling = true;
protected boolean jumping = false;
public GameObject(float x, float y, ObjectId id) {
this.x = x;
this.y = y;
this.id = id;
}
public abstract void tick(LinkedList<GameObject> object);
public abstract void render(Graphics g);
public abstract Rectangle getBounds();
public float getX() { return x; }
public float getY() { return y; }
public float getVelX() { return velX; }
public float getVelY() { return velY; }
public boolean isFalling() { return falling; }
public boolean isJumping() { return jumping; }
public void setX(float x) { this.x = x; }
public void setY(float y) { this.y = y; }
public void setVelX(float velX) { this.velX = velX; }
public void setVelY(float velY) { this.velY = velY; }
public void setFalling(boolean falling) { this.falling = falling; }
public void setJumping(boolean jumping) { this.jumping = jumping; }
public ObjectId getId() { return id; }
}
For example if i want to make a object called Block, i would create a class called Block and extends GameObject like this.
public class Block extends GameObject {
private boolean animate = true;
Texture tex = Game.getInstance();
private int type;
public Block(float x, float y, int type, ObjectId id) {
super(x, y, id);
this.type = type;
}
public void tick(LinkedList<GameObject> object) {
bAnimate.runAnimation();
}
public void render(Graphics g) {
if (type == 0) g.drawImage(tex.red_block[0], (int)x, (int)y, null); // Red Block
if (type == 1) g.drawImage(tex.green_block[0], (int)x, (int)y, null); // Blue Block
if (type == 2) g.drawImage(tex.blue_block[0], (int)x, (int)y, null); // Green Block
if (type == 3) g.drawImage(tex.yellow_block[0], (int)x, (int)y, null); // Yellow Block
if (type == 4) g.drawImage(tex.orange_block[0], (int)x, (int)y, null); // Orange Block
if (type == 5) g.drawImage(tex.pink_block[0], (int)x, (int)y, null); // Pink Block
}
public Rectangle getBounds() {
return new Rectangle((int)x, (int)y, 32, 32);
}
}
I then create a LinkedList like this. An also create 2 methods for adding and removing objects for the list.
protected LinkedList<GameObject> object = new LinkedList<GameObject>();
public void addObject(GameObject object) {
this.object.add(object);
}
public void remove(GameObject object) {
this.object.remove(object);
}
I would then simply add objects to the list like this.
addObject(new Block(x * 32, y * 32, random.nextInt(6), ObjectId.Block));
Sense this post is getting kinda big i will leave the rest to you, if you like i can see you the source code of the project i am using. This is also the same method that "RealTutsGML" uses in his tutorials.
I see that you and using Map.mapx instead of that just write the variable mapx no need for the Map. Also your data should always be private or protected. I also recommend making a variable that holds your map size like this.
private static int mapSize = 2000;
It is just so that if you want to change the map size you don't have to replace more than one number.
I hope this helps you out.
Here is a list of java programming books.

Java GUI change location of a 'tile'

I'm making an A* pathfinding application with a GUI. I have:
- an enum TileType
START(Color.GREEN),
WALL(Color.BLACK),
BLANK(new Color(240, 240, 240)),
END(Color.RED);
- a Grid class
public class Grid extends JPanel {
private final Color lineColour = new Color(200, 200, 200);
private Color defaultColour;
private final int pixelsPerTile;
private final int rows;
private final int columns;
private TileType[][] tiles;
public Grid(int rows, int columns, int pixelsPerTile) {
this.pixelsPerTile = pixelsPerTile;
this.rows = rows;
this.columns = columns;
this.tiles = new TileType[rows][columns];
this.setPreferredSize(new Dimension(rows * pixelsPerTile, columns * pixelsPerTile));
setTile(rows / 2 - 5, columns / 2, TileType.START);
setTile(rows / 2 + 5, columns / 2, TileType.END);
}
public void resetBoard() {
for (int i = 0; i < tiles.length; i++) {
for (int j = 0; j < tiles[0].length; j++) {
if (getTile(i, j) != TileType.START && getTile(i, j) != TileType.END) {
tiles[i][j] = null;
}
}
}
}
public void removeTile(int x, int y) {
tiles[x][y] = TileType.BLANK;
}
public TileType getTile(int x, int y) {
return tiles[x][y];
}
public Point getTile(boolean start) {
for (int x = 0; x < tiles.length; x++) {
for (int y = 0; y < tiles[0].length; y++) {
if (tiles[x][y] == (start ? TileType.START : TileType.END)) {
return new Point(x, y);
}
}
}
return null;
}
public void setTile(int x, int y, TileType tile) {
if (getTile(x, y) != TileType.START && getTile(x, y) != TileType.END) {
tiles[x][y] = tile;
}
}
#Override
public void paint(Graphics g1) {
Graphics2D g = (Graphics2D) g1;
for (int x = 0; x < columns; x++) {
for (int y = 0; y < columns; y++) {
if (getTile(x, y) != null) {
g.setColor(getTile(x, y).getColour());
g.fillRect(x * pixelsPerTile, y * pixelsPerTile, pixelsPerTile, pixelsPerTile);
}
}
}
// have the grid appear on top of blank tiles
g.setColor(lineColour);
for (int x = 0; x < columns; x++) {
for (int y = 0; y < rows; y++) {
g.drawLine(x * pixelsPerTile, 0, x * pixelsPerTile, getHeight());
g.drawLine(0, y * pixelsPerTile, getWidth(), y * pixelsPerTile);
}
}
}
public int getPixelsPerTile() {
return pixelsPerTile;
}
public int getRows() {
return rows;
}
public int getColumns() {
return columns;
}
}
- a Frame class
public class Frame extends JFrame {
private Grid grid;
public Frame() {
grid = new Grid(33, 33, 15); // odd so there is a definitive middle point
this.setAutoRequestFocus(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setTitle("A* Path finder");
this.setBounds(new Rectangle((grid.getRows()) * grid.getPixelsPerTile(),
(grid.getColumns() + 2) * grid.getPixelsPerTile()));
this.setResizable(true);
this.add(grid);
this.setVisible(true);
this.getContentPane().addMouseListener(new MouseLsntr()); // fixes alignment problems
ScheduledThreadPoolExecutor se = new ScheduledThreadPoolExecutor(5);
se.scheduleAtFixedRate(new RedrawGrid(), 0L, 20L, TimeUnit.MILLISECONDS);
}
private class RedrawGrid implements Runnable {
#Override
public void run() {
grid.repaint();
}
}
private class MouseLsntr implements MouseListener {
#Override
public void mouseClicked(MouseEvent me) {
int x = me.getX() / grid.getPixelsPerTile();
int y = me.getY() / grid.getPixelsPerTile();
switch (me.getButton()) {
case MouseEvent.BUTTON1:
if (grid.getTile(x, y) != TileType.WALL) {
grid.setTile(x, y, TileType.WALL);
System.out.println(String.format("(%d, %d) (%d, %d) wall", x, y, x, y));
} else {
grid.removeTile(x, y);
System.out.println(String.format("(%d, %d) (%d, %d) blank", x, y, x, y));
}
break;
}
}
#Override
public void mousePressed(MouseEvent me) {}
#Override
public void mouseReleased(MouseEvent me) {}
#Override
public void mouseEntered(MouseEvent me) {}
#Override
public void mouseExited(MouseEvent me) {}
}
}
and obviously a main class which calls Frame()
When the user left clicks on a grid, they make a WALL at that location. If it's already a WALL, it becomes BLANK. I want the user to be able to move the START and END tile by clicking on it and then dragging to the location they want to stop at, which I'm having trouble doing. Any help would be appreciated since I've been stumped about this for a while now.
You will need to implement the mousePressed and mouseReleased handlers in MouseListener interface, and the mouseDragged handler in MouseMotionListener.
First, make your MouseLsntr extend MouseAdapter class, which implements MouseListener and MouseMotionListener by default.
private class MouseLsntr extends MouseAdapter {
private int dragStartX, dragStartY;
private boolean dragging;
#Override
public void mouseClicked(MouseEvent me) {
int x = me.getX() / grid.getPixelsPerTile();
int y = me.getY() / grid.getPixelsPerTile();
switch (me.getButton()) {
case MouseEvent.BUTTON1:
if (grid.getTile(x, y) != TileType.WALL) {
grid.setTile(x, y, TileType.WALL);
System.out.println(String.format("(%d, %d) (%d, %d) wall", x, y, x, y));
} else {
grid.removeTile(x, y);
System.out.println(String.format("(%d, %d) (%d, %d) blank", x, y, x, y));
}
break;
}
}
#Override
public void mousePressed(MouseEvent me) {
switch (me.getButton()) {
case MouseEvent.BUTTON1:
// Save the drag starting position.
this.dragStartX = me.getX() / grid.getPixelsPerTile();
this.dragStartY = me.getY() / grid.getPixelsPerTile();
this.dragging = true;
break;
}
}
#Override
public void mouseReleased(MouseEvent me) {
switch (me.getButton()) {
case MouseEvent.BUTTON1:
if (this.dragging) {
moveTile(me);
}
this.dragging = false;
break;
}
}
#Override
public void mouseExited(MouseEvent me) {
this.dragging = false;
}
#Override
public void mouseDragged(MouseEvent me) {
if (this.dragging) {
moveTile(me);
}
}
private void moveTile(MouseEvent me) {
int dragEndX = me.getX() / grid.getPixelsPerTile();
int dragEndY = me.getY() / grid.getPixelsPerTile();
TileType dragStartType = grid.getTile(this.dragStartX, this.dragStartY);
TileType dragEndType = grid.getTile(dragEndX, dragEndY);
// If the starting tile was either START or END, move the tile to the destination.
if ((dragEndType == TileType.BLANK || dragEndType == null) &&
(dragStartType == TileType.START || dragStartType == TileType.END)) {
grid.removeTile(this.dragStartX, this.dragStartY);
grid.setTile(dragEndX, dragEndY, dragStartType);
// update the drag starting points
this.dragStartX = dragEndX;
this.dragStartY = dragEndY;
}
}
}
Next, add your MouseLsntr instance as a MouseMotionListener as well, so that mouseDragged handler is called when you are dragging. Note that you should not create two separate instances of MouseLsntr, because the member fields should be shared. You should do it like the following in the Frame() constructor.
MouseLsntr listener = new MouseLsntr();
this.getContentPane().addMouseListener(listener);
this.getContentPane().addMouseMotionListener(listener);
After doing this, the TileType.START / TileType.END tiles will follow the mouse when being dragged.

Images disappear when coordinates are updated, JPanel

Bah. I figured out the bug. Of course it was absurdly simple. The overridden update under MovingPanelItem needs to be written as follows:
#Override
public void update( int x, int y )
{
xCoord = xCoord + getxStep();
yCoord = yCoord + getyStep();
}
FULL DISCLOSURE: This is homework.
The PROBLEM:
Upon each Key listener event the screen should be updated and the moving objects should move. Currently, while the objects show up initially, if I press the prescribed key they disappear.
Also, all of the PanelItem's are stored in an ArrayList ( in another class ). All of the objects which are not subclasses of MovingPanelItem remain on the screen upon the KeyEvent.
I know I've left a lot to the imagination so if more detail is needed please let me know.
The superclass:
public class PanelItem
{
private Image img;
protected int xCoord;
protected int yCoord;
protected int width;
protected int height;
//constructor
public SceneItem( String path, int x, int y, int w int h )
{
xCoord = x;
yCoord = y;
setImage( path, w, h );
}
public void SetImage( String path, int w, int h )
{
width = w;
height = h;
img = ImageIO.read(new File(path));
}
//to be Overriden
public void update( int width, int height )
{
}
}
The Subclass:
public class MovingPanelItem extends PanelItem
{
private int xStep, yStep;
// x & y correspond to the coordinate plane
// w & h correspond to image width and height
// xs & ys correspond to unique randomized 'steps' in the for the x and y values
public MovingSceneItem(String path, int x, int y, int w, int h, int xs, int ys)
{
super( path, x, y, w, h);
setxStep(xs);
setyStep(ys);
update( x, y );
}
#Override
public void update( int x, int y )
{
this.xCoord = x + getxStep();
this.yCoord = y + getyStep();
}
}
(In response to Eels)
The panel/window itself is contained within the following class:
public class Panel extends JPanel {
protected ArrayList<PanelItem> panelItems;
private JLabel statusLabel;
private long randomSeed;
private Random random;
public Panel(JLabel sl) {
panelItems = new ArrayList<PanelItem>();
statusLabel = sl;
random = new Random();
randomSeed = 100;
}
private void addPanel() {
addPanelItems(10, "Mouse");
}
private void addPanelItems(int num, String type) {
Dimension dim = getSize();
dim.setSize(dim.getWidth() - 30, dim.getHeight() - 30);
synchronized (panelItems) {
for (int i = 0; i < num; i++) {
int x = random.nextInt(dim.width);
int y = random.nextInt(dim.height);
if (type.equals("Person")) {
int xs = random.nextInt(21) - 10;
int ys = random.nextInt(21) - 10;
panelItems.add(new Mouse(x, y, xs, ys));
}
}
repaint();
}
// causes every item to get updated.
public void updatePanel() {
Dimension dim = getSize();
synchronized (panelItems) {
for (PanelItem pi : panelItems) {
pi.update(dim.width, dim.height);
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
synchronized (panelItems) {
for (PanelItem pi : panelItems) {
pi.draw(g);
}
}
}
}
KeyListener class within the test class:
private class MyKeyListener extends KeyAdapter
{
#Override public void keyTyped(KeyEvent e)
{
if(e.getKeyChar() == 'f') {
panel.updatePanel();
panel.repaint();
}
// other key events include reseting the panel &
// creating a new panel, both of which are working.
}
}
Within the above code the only code I'm allowed to change ( & the only code I've written ) is the subclass MovingPanel item.

Categories