What I'm trying to accomplish is adding 1 to the all the numbers in shipX array list, question is, how? I want to do this when the method move() is called, but how would I make this happen, as I'm new with arrays
class Ship
{
public void paint(Graphics g)
{
int shipX[] = {500,485,500,515,500};
int shipY[] = {500,485,455,485,500};
g.setColor(Color.cyan);
g.fillPolygon(shipX, shipY, 5);
}
public void move()
{
}
}
To start, you will have to move your arrays for points outside the local scope of paint() and into the class so that move() has access to the current values. You would increment in the move() method and call whatever routine you use to redraw your component.
class Ship
{
//make your polygon points members of the class
//so that you can have state that changes
//instead of declaring them in the paint method
int shipX[] = {500,485,500,515,500};
int shipY[] = {500,485,455,485,500};
//set these to the amount you want per update. They can even be negative
int velocityX = 1;
int velocityY = 1;
public void paint(Graphics g)
{
g.setColor(Color.cyan);
g.fillPolygon(shipX, shipY, 5);
}
public void move()
{
//add 1 to each value in shipX
for (int i=0; i<shipX.length; i++)
{
shipX[i] += velocityX;
}
//add 1 to each value in shipY
for (int i=0; i<shipY.length;i++)
{
shipY[i] += velocityY;
}
//call whatever you use to force a repaint
//normally I would assume your class extended
//javax.swing.JComponent, but you don't show it in your code
//if so, just uncomment:
//this.repaint();
}
}
Although I should point out that the repaint() method on JComponent does need to be called from the correct Swing thread, as pointed out in this answer.
If you are also trying to animate the movement, you can check out the Java Tutorial on Swing timers to call your move() method on a schedule. You could also use an ActionListener on a button to either control the Timer or on a button to move the object manually once per click.
All you have to do is iterate through the array and modify the value of each index:
for (int i = 0; i < shipX.length; i++)
{
shipX[i]++;
}
Increase the numbers one by one...
for (i=0; i<shipX.length; i++)
{
shipX[i]++; // same as shipX[i] = shipX[i] +1
}
for (i=0; i<shipY.length;i++)
{
shipY[i]++;
}
Related
Im doing an assignment for school. I have to create 30 randomly colured GameObjects in random locations. I have to use 2 classes, a GameObject class which contains the GameObject data, x and y co-ordinates and colour, plus the move and paint method... and a main MovingSquaresApplication which puts the GameObjects into an array and calls the paint() and move() methods... the current program compiles, runs, paints 60 squares (paint() and repaint()) but no animation. I've looked at a lot of different posts but still cant get it right. Any help would be great. Here is the code.....
*edited new code
import java.awt.*;
import javax.swing.*;
public class MovingSquaresApplication extends JFrame implements Runnable {
//member data
private static final Dimension WindowSize = new Dimension(600,600);
private static final int NUMGAMEOBJECTS = 30;
private GameObject[] gameObjectsArray = new GameObject[NUMGAMEOBJECTS];
private int i,j;
//constructor
public MovingSquaresApplication(){
this.setTitle("MovingSquaresApplication");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Display the window, centered on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - WindowSize.width/2;
int y = screensize.height/2 - WindowSize.height/2;
setBounds(x, y, WindowSize.width, WindowSize.height);
setVisible(true);
for (i=0; i<gameObjectsArray.length; i++){ //fills array with GameObjects
GameObject NewSquare = new GameObject();
gameObjectsArray[i] = NewSquare;
}
Thread t = new Thread(this); //creates and stars a thread
t.start();
}
//threads entry point
public void run(){
while (true){
try {
Thread.sleep(20);
for (j=0; j<gameObjectsArray.length; j++){
gameObjectsArray[j].move();
repaint();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//applications paint method
public void paint (Graphics g){
super.paintComponents(g);
for (i=0; i<gameObjectsArray.length; i++){
gameObjectsArray[i].paint(g);
}
}
//applications entry point
public static void main(String[] args){
MovingSquaresApplication w = new MovingSquaresApplication();
}
}
and the GameObject class
import java.awt.*;
public class GameObject {
//member data
private int x,y,xvel=2,yvel=2;
private Color c;
public GameObject(){
x = (int) (Math.random( )*600);
y = (int) (Math.random( )*600);
int R = (int) (Math.random( )*256);
int G = (int)(Math.random( )*256);
int B= (int)(Math.random( )*256);
c = new Color (R, G, B);
}
//public interface
public void move(){
x += xvel;
y += yvel;
if(x<10)
{
xvel = 2;
}
else if(y<30)
{
yvel = 2;
}
else if(x>=560)
{
xvel = -2;
}
else if(y>=560)
{
yvel = -2;
}
}
public void paint(Graphics g){
g.setColor(c);
g.fillRect(x, y, 30, 30);
}
}
Thanks for all the help, much appreciated
Thanks for the help, I didnt create a class that extends JPanel, i simply put
super.paintComponent(g);
in the paint method, not sure if thats good practice but it worked....also on a sidenote i haven't seen this before
for (GameObject gameObject : gameObjectArray)
what exactly does this do compared to the loop i've used?
You need to paint within the paintComponent method of a JPanel (as I'm sure that you've read,.... and so I recommend that you do just that. That you
Fill your GameObjectsArray with GameObjects, and do so not within any painting method, but on GUI construction
Create a JPanel and override its paintComponent method just as the Swing painting tutorials tell you to do
Call the super's paintComponent method within your override (again as the tutorials will tell you to do)
iterate through your GameObjectsArray (but rename it gameObjectsArray since its a variable not a class) within the paintComponent method
call each GameObject's paint method within that same for loop.
edit: check out this code of yours:
GameObject MoveSquare = new GameObject();
for (y = 0; y < GameObjectsArray.length; y++) {
MoveSquare.move();
}
What you're doing is creating a completely new GameObject object, MoveSquare, and are trying to move it within the for loop, meanwhile you're not touching any of the GameObjects held within the gameObjectsArray. Do you see your mistake here?
Edit 2
Also you're using the y variable as the array index, the same variable that you're using to figure out the y-axis bounds of your GUI -- don't do this. Use a completely independent variable.
Edit 4
And here:
public void paint(Graphics g) {
for (y = 0; y < GameObjectsArray.length; y++) {
GameObject NewSquare = new GameObject();
if (GameObjectsArray[y] == null) {
GameObjectsArray[y] = NewSquare;
NewSquare.paint(g);
}
}
}
You're creating new GameObject variables with each call to paint, ignoring any that already may be present in the array(??). Painting methods should be for painting and painting only. Again, fill your GameObject array with new GameObject items once and in your class constructor, not in a painting method.
You're doing a lot of guessing here, and throwing code at the wall and seeing what sticks is not a good heuristic for creating a program. Instead plan each step on paper before committing code to IDE.
Edit 5
Your if conditions within the GameObject move method need to be fixed. But once you get the code running, you'll see exactly what I mean, as you'll see all your GameObjects running off of the page.
Edit 6
I'm not going to show you all your code, but again, you'll want to create a class that extends JPanel, override its paintComponent method, and that method will be quite simple and look like this:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // do housekeeping painting
// note that I've renamed the array to gameObjectArray
for (GameObject gameObject : gameObjectArray) {
gameObject.paint(g); // this is all you need to call
}
}
Likewise, the run method would be something like:
#Override
public void run() {
while (true) {
try {
Thread.sleep(SLEEP_TIME); // constant for the sleep time
} catch (InterruptedException e) {
e.printStackTrace();
}
// again note that the array has been renamed
for (GameObject gameObject : gameObjectArray) {
gameObject.move(); // this is all that needs to be called here
}
repaint();
}
}
Edit next :)
You're creating two Thread objects and starting them both -- don't do that. Only one will do.
class DrawPane extends JPanel
{
//size is the size of the square, x and y are position coords
double size = 1, x = 0, y = 0;
double start = (-1) * size;
public void paintComponent(Graphics shape)
{
for(x = start; x <= scWidth; x += size)
{
shape.drawRect((int)x, (int)y , (int)size, (int)size);
//When a row is finished drawing, add another
if(x >= scWidth)
{
x = start; y += size;
}
//Redraws the entire grid; makes the for loop infnite
else if(y >= scHeight)
{
x = start; y = start;
}
}
}
}
I'm confused as to why JPanel refuses to work with the loop once I make it infinite. How would I go about allowing it to do so?
When you make the loop "infinite" you effectively tie up and freeze the Swing event thread preventing Swing from doing anything. Instead use a Swing Timer to drive your animation.
e.g.,
class DrawPane extends JPanel {
//size is the size of the square, x and y are position coords
double size = 1, x = 0, y = 0;
double start = (-1) * size;
public DrawPane() {
int timerDelay = 200;
new Timer(timerDelay, new ActionListener(){
public void actionPerformed(ActionEvent e) {
x += size;
if (x >= scWidth) {
x = start;
y += size;
}
if (y >= scHeight) {
x = start;
y = start;
}
repaint();
}
}).start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g); // Don't forget to call this!
g.drawRect((int)x, (int)y , (int)size, (int)size);
}
}
The paint function is supposed to update the Paint and get out of the way. You really shouldn't be putting in complex logic and definitely not infinite loops there.
Just do what you have (except get rid of the reset stuff that makes your loop infinite) and put repaint() in an infinite loop (preferably with some timer logic) somewhere else in your program.
It will never break out of the paintComponent loop and update the GUI. The GUI will only update once the paintComponent method finishes. If you want to make the loop infinite, you need to take the code out of your event handler and be calling repaint() from elsewhere, possibly using a timer to do so.
Hello everyone I am having trouble with painting over coins that the user intersects with. What I want this code to do is when the user sprite intersects with any of the ten coin images it paints over the coin so that it no longer appears on the screen (also need to add in some kind of counter so that when the user collects all ten coins it will stop the thread, and say "You Win!"). My question is how would I go about doing this because I have tried using repaint() in the if statements, and it is not compiling correctly anymore. Any help on how to paint over the coins, and possibly even add some kind of counter (thinking a for loop would come in handy) would be greatly appreciated! Here is the code:
public void paint(Graphics g)
{
g.clearRect(0, 0, this.getWidth(), this.getHeight());
one.paintComponent(g);
two.paintComponent(g);
three.paintComponent(g);
four.paintComponent(g);
five.paintComponent(g);
six.paintComponent(g);
seven.paintComponent(g);
eight.paintComponent(g);
nine.paintComponent(g);
ten.paintComponent(g);
monster.setLocation(r.nextInt(10) - 5 + monster.x, r.nextInt(10 - 5 + monster.y));
monster.paintComponent(g);
user.paintComponent(g);
if(user.intersects(one))
{
}
if(user.intersects(two))
{
}
if(user.intersects(three))
{
}
if(user.intersects(four))
{
}
if(user.intersects(five))
{
}
if(user.intersects(six))
{
}
if(user.intersects(seven))
{
}
if(user.intersects(eight))
{
}
if(user.intersects(nine))
{
}
if(user.intersects(ten))
{
}
if(user.intersects(monster))
{
g.setFont(new Font("Serif", Font.BOLD, 35));
g.drawString("YOU HAVE DIED, YOU LOSE!", 100, 100); //Prints this when you lose
thread.interrupt(); //Stopping the thread if you die
}
}
At first, you should put the coins in a list. Then, if there's an interection, you simply remove the item (coin) of the list. Like this:
private List<Coin> coins;
public ClassConstructor() {
coins = new ArrayList();
coins.add(new Coin(type value,...)); //this ten times if every Coin is different from other
//or this if every Coin are same:
for (int i = 0; i < 10; i++) {
coins.add(new Coin(type value,...));
}
}
public void update() {
//whatever
for (int i = coins.size(); i >= 0; i--) {
if (user.intersects(coins.get(i))) {
coins.remove(i);
//...
}
}
}
public void paint(Graphics g) {
for (int i = coins.size(); i >= 0; i--) {
coins.get(i).paintComponent(g);
}
}
Now, you shouldnt end a Thread with thread.interrupt(). If that thread is your game loop, you should send a flag that ends the loop. The Thread of you game loop:
#Override
public void run() {
while (running) { //boolean running
update();
paint(g);
}}
And, finally, your update will be like:
public void update() {
//whatever
for (int i = coins.size(); i >= 0; i--) {
if (user.intersects(coins.get(i))) {
coins.remove(i);
//...
}
}
if (user.intersects(monster)) {
youThread.setRunning(false);
try {
gameLoopThread.join(); //"wait" until thread ends
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
This code is taken from my current project (that is working), I tried adjusting it to your project.
private void render () {
BufferStrategy bufferstrategy = getBufferStrategy ();
if (bufferstrategy == null) {
createBufferStrategy(3);
return;
}
Graphics g = bufferstrategy.getDrawGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, getWidth(), getHeight());
paint (g);
g.dispose();
bufferstrategy.show();
}
render() is called from run(), where the Thread is.
Let's break it down and see if it can help you.
It gets a BufferStrategy for how many images to have ready. It can be set to anything like you like within reason. 2 - 4 will do the trick. One can even work.
It sets your current BufferStrategy to your Graphics.
It then fills the screen with the color of white (could be a clear as well).
Then it paints all components, in your case it calls paint (Graphics g) while in my case it iterates through all drawable objects.
It re-renders everything as it now should look.
Hope you take some points out from this.
Off the top of my head, put while(true) within your Run() method (you said you were using a thread) and call repaint() within the loop, at the end of the loop (within a try/catch) put something like //thread//.sleep(allotted time) This will stop the thread for the set amount of Milliseconds. Within the Javadoc of repaint() you'll see that it calls the nearest paint(Graphics g) method. By doing this you can access your paint() method from wherever you are in your program.
My suggestion to the coin's is make it it's own class. The class would look similar to this:
public class Coin{
int x;
int y;
public void Coin(int x, int y, Graphics g){
Graphics2D g2 = (Graphics2D) g;
Image img1 = (//File Location);
g2.drawImage(img1, x, y, //this);
//If you have trouble with the ImageObserver (this part) try //class name of the applet.this
this.x = x;
this.y = y;
g2.finalize();
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}
After that, in your paint method you could make 10 Coin objects and use g which you instantiate in the parameters. You could then make an array of Coin objects and add 10 Coins that you make in your paint method manually (yeah, it's a pain) (you have to make them in paint to pass the Graphics variable)
Coin[] coins = new Coin[10];
Is how you make the array, by the way. After you make the array of coin's, then make a for loop in your paint method. It should look something like this:
for(int i = 0; i < coins.length; i++){
if(coins[i].getX == //user X && coins[i].getY == //user Y){
g.clearRect(coins[i].getX, coins[i].getY, //Coin radius, //Coin radius);
}
}
This will make a clear rectangle be drawn over wherever the Coin is at if the user's X and Y is equal to the Coin's X and Y.
I am generating 100 ovals as particles in the initialization method and then I want to move them by a certain amount(lets say x) for n number of iterations. I have written the following code snippet to do that.
private void drawNParticles(Graphics g)
{
ArrayList<Integer> list;
list = new ArrayList<Integer>(Collections.nCopies(n, 0));
for(int i=0;i<list.size();i++)
{
generateParticle(g);
}
}
private void generateParticle(Graphics g)
{
int radius = 4;
ArrayList<Integer> list= new ArrayList<Integer>();
list=positionParticles(particle_x,particle_y);
g.setColor(Color.RED);
g.fillOval(list.get(0),list.get(1), radius, radius);
}
private ArrayList<Integer> positionParticles(int x, int y)
{
int radius = 4;
ArrayList<Integer> list= new ArrayList<Integer>();
if(this.particle_counter==0)
{
x=randomInteger(2,678); // bounds of x between which the particles should be generated
y=randomInteger(2,448); // bounds of y between which the particles should be generated
x=x-(radius/2);
y=y-(radius/2);
if((x<251&&x>149)&&(y<266&&y>224))
{
x=0;
y=0;
positionParticles(x,y);
}
if((x<541&&x>499)&&(y<401&&y>299))
{
x=0;
y=0;
positionParticles(x,y);
}
this.particle_counter++;
}
else
{
setXPosition_particle(x);
setYPosition_particle(y);
}
list.add(x);
list.add(y);
return list;
}
public void setXPosition_particle(int x)
{
this.particle_x=x+5;
System.out.println("Particle_X:"+this.particle_x);
}
public void setYPosition_particle(int y)
{
particle_y=y+5;
System.out.println("Particle_Y:"+this.particle_y);
}
What I want is that each particle's position should be incremented by 5. But in the output, every particle gets the same value. I am getting a diagonal line across my JPanel. What should I do to access each instance variable separately?
Why don't you just create a Particule class and maintain a List<Particule> ?
Your first for loop is messing up as is the generateParticle method. You should pass the index, i, into the method, you should not create a new and completely unrelated ArrayList inside the generateParticle method but instead use the ArrayList class field, list, inside of the method.
I also recommend that you not use the paint or paintComponent method to move your particles as you do not have full control over when or if it is called. Instead separate the moving of particles and their drawing by doing the moving say in a Swing Timer, and then simply iterating through the List in the paintComponent method, drawing each point.
kinda new to swing and making guis in general, I have been using the drawLine method to create a "floors" and it has been working for the variables of the coordinates are local the the paintComponent class, however I want to change the coordinates using an actionListerner / Timer, so I need the variables to be accessible to the whole class.
This is probably a real simple fix (??) and I'll look like a fool for asking it here, but I can't work it out.
Here is the code.
class Elevator extends JPanel implements ActionListener {
private int numberOfLines = 0;
private int j = 60;
int yco = j - 125;
final private int HEIGHT = 50;
final private int WIDTH = 80;
final private boolean UP = true;
final private int TOP = 60;
final private int BOTTOM = j - 125;
private int mi = 5;
private Timer timer = new Timer(100, this);
public Elevator(int x) {
this.numberOfLines = x;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < numberOfLines; i++) {
g.drawLine(0, j, getWidth(), j);
j += 75;
}
g.drawRect(getWidth() / 2, yco, WIDTH, HEIGHT);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
Any help is appreciated thanks in advance.
The reason your lines are not showing now that your variables (specifically j in your example code) are class variables, is that they are "remembering" state between calls to paintComponent(). Specifically, when j was local, it always got set back to its initial value (presumably j=60). Now however, it gets incremented in your for loop in the line
j += 75;
and never reset to a lower value. This means the second or third time that paintComponent() gets called, the value of j is too large, and your lines are being drawn outside the visible area (off screen). A Java Swing component can easily have its paintComponent() method called two, three, or more times before the component is even rendered on the screen, which is why your lines are no longer getting drawn (well, technically they are getting drawn, just not anywhere you can see them).
To fix this, you can add to your paintComponent() method the single line
j = 60;
just before the for loop. But at this point, you might as well just keep j local (unless you need to read its value but not change it with the timer).
Alternatively, if j needs to change over time, just make sure it gets set inside actionPerformed() by the timer, thenwork with a copy of the value inside of paintComponent() instead of directly with the value of j. As an example:
public void paintComponent(Graphics g) {
...
int jCopy = j;
for (int i = 0; i < numberOfLines; i++) {
g.drawLine(0, jCopy, getWidth(), jCopy);
jCopy += 75;
}
...
}
public void actionPerformed(ActionEvent e) {
...
j += 5;
//If you don't cap it at some max,
//it will go off the bottom of the screen again
if (j > 300) {
j = 60;
}
...
}
This will help stop consistency issues that could be caused by modifying j in both paintComponent() and actionPerformed().