I'm making a small game in which the Main class holds all the objects and variables and calls the methods within the classes themselves that do most of the work. Pretty standard. Unfortunately, that means that many of the variables I need are in the Main class where I can't access them.
For instance, as a test I wanted a ball to bounce around the screen, simple enough, but I need the dimensions of the screen, which I can get easily using the getSize() method in the main class. But when I create the Ball class which will bounce around, I can't access the getSize() method because it is in the Main class. Is there anyway to call it?
I know I can pass the variables to the Ball class in the constructor or for each method I need, but I want to see if there is some way I can take whichever variables I need when I need them, rather than passing it all the information whenever I make a new object.
Main.class
public void Main extends JApplet {
public int width = getSize().width;
public int height = getSize().height;
public void init(){
Ball ball = new Ball();
}
}
Ball.class
public void Ball {
int screenWidth;
int screenHeight;
public Ball(){
//Something to get variables from main class
}
}
Pass the variables you need to your objects. You can even create a singleton class containing all the constants/configurations that your classes need.
Example given:
Constants class
public class Constants {
private static Constants instance;
private int width;
private int height;
private Constants() {
//initialize data,set some parameters...
}
public static Constants getInstance() {
if (instance == null) {
instance = new Constants();
}
return instance;
}
//getters and setters for widht and height...
}
Main class
public class Main extends JApplet {
public int width = getSize().width;
public int height = getSize().height;
public void init(){
Constants.getInstance().setWidth(width);
Constants.getInstance().setHeight(height);
Ball ball = new Ball();
}
}
Ball class
public class Ball {
int screenWidth;
int screenHeight;
public Ball(){
this.screenWidth = Constants.getInstance().getWidth();
this.screenHeight= Constants.getInstance().getHeight();
}
}
Another way can be to start the object instance with the parameters you need. Example given:
Main class
public class Main extends JApplet {
public int width = getSize().width;
public int height = getSize().height;
public void init(){
Ball ball = new Ball(width, height);
}
}
Ball class
public class Ball {
int screenWidth;
int screenHeight;
public Ball(int width, int height){
this.screenWidth = width;
this.screenHeight= height;
}
}
There are more ways to achieve this, just look out yourself and choose the one you think it would be better for your project.
you can access them using simply two arg constructor.
public void init(){
Ball ball = new Ball(width,height);
}
public Ball(width,height){
//access variables here from main class
}
why do not this way:
public void Main extends JApplet {
public int width = getSize().width;
public int height = getSize().height;
public void init(){
Ball ball = new Ball(width, height);
}
public void Ball {
public Ball(int screenWidth, int screenHeight){
//use the variables
}
Related
What is the good way to access final fields from other class and why.
A) Isolating it from other class by making it private and giving the functionality in the getter and setter method
public class Game extends JPanel {
private final Racquet racquet;
public Game() {
racquet = new Racquet(this);
}
}
public class Ball {
private Game game;
Ball(final Game game) {
this.game = game;
}
void move(int speed) {
if (collision()) {
y = game.getRacquet().getTopY() - DIAMETER;
}
}
}
public class Racquet {
final Game game;
public Racquet(final Game game) {
this.game = game;
}
public int getTopY() {
return Y;
}
}
B) Keeping it default and use the variable.methodname directly.
public class Game extends JPanel {
final Racquet racquet;
}
public class Ball {
void move(int speed) {
if (collision()) {
y = game.racquet.getTopY() - DIAMETER;
}
}
}
public class Racquet {
final Game game;
public Racquet(final Game game) {
this.game = game;
}
public int getTopY() {
return Y;
}
}
do accessing final fields directly leads to improved performance?
Instead of using the getter to move the Racket, it would be best to have a method it do it for you internally.
void move(int speed) {
if (collision()) {
racket.move(diameter)
}
}
//inside racket
public int move(int diameter){
return this.Y - diameter;
}
Or if you want, split the move into moveUp, moveDown, etc.. and return the value of the calculation after you pass the diameter. This will be dependent on a number of things, for example, the position of the ball. You can check the position of the ball and decided which method to call and move the racket.
It might be best to think about it realistically.
You could have a Player class:
Responsible for determining the position of the ball.
Moving the Racket
In reality your Racket, won't be aware of where the Ball is, or the Ball won't be aware your using a Racket to hit it, the Player is aware of it.
If you want to follow OOP guidelines, then don't access variables directly(i.e public) instead let the methods to do the work for you, and give you the result, it's a method of Tell, Don't Ask. Keep the getters for display purposes if needed.
I'm not sure why but in my paintComponent method, the fillOval function is not letting me pass in my other classes coordinates. It comes up with :
'Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException'
all the rectangles draw fine but just not the oval. Here is the paintComponent() method.
public void paintComponent(Graphics graphics){
graphics.setColor(Color.BLACK);
graphics.fillRect(0,0,600,450);
graphics.setColor(Color.WHITE);
graphics.fillRect(290,0,15,450);
graphics.fillRect(leftPaddle.getXPos(),leftPaddle.getYPos(),10,85);
graphics.fillRect(rightPaddle.getXPos(),rightPaddle.getYPos(),10,85);
graphics.fillOval(ball.getxPos(),ball.getyPos(),ball.getWidth(),ball.getHeight());
}
And here is my Ball class (the class which bears the coordinates).
public class Ball {
int xPos = 140;
int yPos = 50;
int width = 15;
int height = 15;
public int getWidth() {
return width;
}
public int getxPos() {
return xPos;
}
public int getyPos() {
return yPos;
}
public int getHeight() {
return height;
}
}
This is probably quite an easy fix, but I am relatively new to java, so excuse any formatting mistakes, etc.
Here is where I get the object from the MainClass :
public class PaintComponents extends JPanel{
Paddle leftPaddle;
Paddle rightPaddle;
Ball ball;
public PaintComponents(Paddle leftPaddle, Paddle rightPaddle, Ball ball) {
this.leftPaddle = leftPaddle;
this.rightPaddle = rightPaddle;
this.ball = ball;
}
As its showing NullPointerException
you might not have created the object "ball" of class Ball
try adding:
Ball ball=new Ball();
in public void paintComponent(Graphics graphics)
before using "ball".
I didn't see where did you get the ball. So,
You can instantiate the Ball class like Ball ball = new ball() before the fillOval() happen. Or
You can mark all the fields and methods as static then use Ball.getSth() instead.
Answer is written by me in the bottom of the question
I want to get a lot of 'Ates' objects in a frame. I tried a lot of examples but always failed.
In this context, I want to see a lot of rectangles which are going to left. However, there is just one and it is going faster and faster...
It does not show more than one object at the same time. Can you tell me what is the problem?
I used this code:
public class GamePanel extends JPanel
{
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.BLACK);
for(Ates a1 : StartGame.alist) // alist is an arraylist for Ates class objects
{
g.fillRect(a1.getX(), a1.getY(), 20, 20);
}
...
Example creating:
public void sentAtes()
{
r = rand.nextInt(471)+60;
Ates a = new Ates(r);
alist.add(a);
}
Ates class:
public Ates(int a)
{
x = 700;
y = a;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public void setX( int a )
{
x = a;
}
public void setY( int a )
{
y = a;
}
StartGame class:
public class StartGame extends JFrame implements KeyListener, ActionListener
{
protected static ArrayList<Ates> alist = new ArrayList<Ates>();
public static int cen = 0;
...
public StartGame()
{
jp = new GamePanel();
add(jp);
...
int delay = 10;
ActionListener taskPerformed = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
cen++;
if(cen > 50)
{
cen = 0;
sentAtes();
}
for(Ates a1 : alist)
{
a1.setX(a1.getX()-1);
}
repaint();
}
};
new Timer(delay,taskPerformed).start();
...
Info: If there is only one object, it is going left as expected.
Answer to my question.
In Ates class, you should not use static word for variables and use this. prefix to set them.
This should be work.
public class Ates extends JFrame
{
protected int x;
protected int y;
public Ates(int a)
{
this.x = 700;
this.y = a;
}
Ok the only other thing I can see is that your StartGame() is only initialised once. Therefore your new Timer is only called once. Because it is the timer that is causing the ActionListener to be created it is only ever created and run through once and therefore can never reach the stage where it will create another rectangle. The actionPerformed() method only runs once in the program as there is no action or loop to cause it to run again.
So what I want to achieve, is to create a simple program that lets the user create rectangles on the screen and then move them around.
I know that I can declare a new object in the code (i.e rectangle i = new rectangle(x,y,sizex,sizey)) however that will create only one, moreover it forces me to declare it in the code:
block1 = new block
block2 = new block
etc
Question is: How can I let the user create infinite rectangles with the use of lets say a button (not necessarily a button, it can be anything) and then let the user be capable of modyfing them (location/size etc).
Examples would be nice. I just feel there is a better way than declaring a gazillion objects in the code and then displaying them one by one. In C++ i could declare a malloc expandable container that would just hold the values, and then just display things using these values, not sure for java.
Simple code for reference:
public static void main(String[] args){
JFrame frame = new JFrame("A.L.T.E.S");
//Container container = frame.getContentPane();
frame.setSize(1024, 768);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Block object = new Block(10,10,20,20);
frame.add(object);
object.reDraw();
}
public class Block extends JPanel{
int yPos;
int xPos;
int xSize;
int ySize;
public Block(int xPos, int yPos, int xSize, int ySize){
this.xPos = xPos;
this.yPos = yPos;
this.xSize = xSize;
this.ySize = ySize;
}
public void setYPos(int yPos){
this.yPos = yPos;
}
public void setXPos(int xPos){
this.xPos = xPos;
}
public void setXSize(int xSize){
this.xSize = xSize;
}
public void setYSize(int ySize){
this.ySize = ySize;
}
public int getYPos(){
return yPos;
}
public int getXPos(){
return xPos;
}
public int getYSize(){
return ySize;
}
public int getXSize(){
return xSize;
}
public void reDraw(){
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(xPos, yPos, xSize, ySize);
}
}
Nothing in Java is simple.
First, Java already has a Rectangle class that holds the origin and size of a Rectangle. In your code, you're making all the rectangles blue. Suppose you want the user to set the color of a Rectangle. You can define your Block class like this.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
public class Block {
private Color color;
private Rectangle rectangle;
public Block(int x, int y, int width, int height) {
this(new Rectangle(x, y, width, height));
}
public Block(Rectangle rectangle) {
this.rectangle = rectangle;
this.color = Color.BLUE;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public Rectangle getRectangle() {
return rectangle;
}
public void draw(Graphics g) {
g.setColor(getColor());
g.fillRect(rectangle.x, rectangle.y,
rectangle.width, rectangle.height);
}
}
Next, you need a model class to hold all of the Blocks that your user defines.
Something like this BlockList class.
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
public class BlockList {
private List<Block> blockList;
public BlockList() {
this.blockList = new ArrayList<Block>();
}
public void init() {
this.blockList.clear();
}
public void addBlock(Block block) {
this.blockList.add(block);
}
public void draw(Graphics g) {
for (int i = 0; i < blockList.size(); i++) {
blockList.get(i).draw(g);
}
}
}
Now that you have your GUI model defined, you would build your GUI. Your drawing JPanel would call the draw method in your BlockList class.
I strongly suggest that you go through the Oracle tutorial on Swing. Go through the complete tutorial before you attempt to create a Swing GUI.
In java, use a Collection. In this case, use a List. You can create an ArrayList<Block>, then invoke add to add new rectangles. Then, you can iterate through this collection by using iterator, then calling hasNext and next on the iterator to find all the elements. I'm sure this brief hypnosis is going to be confusing, and if so, check out the Java Tutorial on Collections, which explains everything in all the detail you are going to need.
Currently I try to make a game of chess. This, the main class, calls a JPanel subclass, on which I draw the figures.
package schach;
public class schach extends JFrame {
private SpielFeld spiel = new SpielFeld();
public schach(String title) {
Container cp = getContentPane();
cp.add(spiel, BorderLayout.CENTER);
}
public static void main(String[] args) {
new schach("Schach");
}
}
Then it continues with SpielFeld, the JPanel subclass, which is supposed to draw the figures and the board:
package schach;
public class SpielFeld extends JPanel {
private Image brettimg = new ImageIcon("schach\\sprites\\brett.png").getImage();
private Image bauerWimg = new ImageIcon("schach\\sprites\\bauerW.png").getImage();
private ArrayList<Figur> figuren = new ArrayList<Figur>();
private Bauer bauerW1 = new Bauer(6, 0);
public SpielFeld() {
figuren.add(bauerW1);
}
#Override
public void paintComponent(Graphics g) {
g.drawImage(brettimg, 0, 0, null);
for (int i=0; i<figuren.size(); i++) {
g.drawImage(bauerWimg, (int) figuren.get(i).getPoint().getX()*64, (int) figuren.get(i).getPoint().getY()*64, null);
}
}
}
Now I do get a NullPointerException. I think this is because of the order in which "spiel" is created, the paintComponent is called (by default, uppon adding the JFrame to the ContentPane or something?) and the ArrayListed created and filled. I tried to comment out stuff to see how it work, but can't seem to figure it out. How does it work and how can I fix this? I tried to delete the hopefully unimportant stuff.
Figur.java
package schach;
public class Figur {
Point posi;
public Figur(int x, int y) {
posi.setLocation(x, y);
}
public Point getPoint() {
return posi;
}
}
Bauer.java
package schach;
public class Bauer extends Figur {
boolean zug = false;
public Bauer(int x, int y) {
super(x, y);
}
}
#skirsch
This?
Exception in thread "main" java.lang.NullPointerException
at schach.Figur.<init>(Figur.java:10)
at schach.Bauer.<init>(Bauer.java:8)
at schach.SpielFeld.<init>(SpielFeld.java:29)
at schach.schach.<init>(schach.java:10)
at schach.schach.main(schach.java:31)
In the class Figur the Point posi is not initialized and therefor null.
Replace
public Figur(int x, int y) {
posi.setLocation(x, y);
}
by
public Figur(int x, int y) {
posi = new Point(x, y);
}
to eliminate the NullPointer Exception.