#103 Members - Reputation: 238
Posted 12 August 2012 - 08:43 PM
[source lang="java"]import java.applet.Applet;import java.awt.Color;import java.awt.Component;import java.awt.Event;import java.awt.Graphics;import java.awt.Image;import java.awt.Rectangle;import java.util.ArrayList;import java.util.concurrent.TimeUnit;public class game extends Applet implements Runnable{ static final int WIDTH = 450; //set screen height static final int HEIGHT = 450; // set screen width private Image dbImage; private Graphics dbg; public static long NEW_DOT_FREQ = TimeUnit.SECONDS.toMillis(3); public long lastUpdateTime; public long timeSinceLastNewDot; public ArrayList<Ball> BALLS; //arraylist to store balls Color[] color = {Color.red, Color.blue, Color.green, Color.yellow, Color.magenta, Color.black}; int colorIndex; static final int NUM_OF_BALLS = 4; int i; int t; MainBall mainBall = new MainBall(100, 100, 10, 10, 0, 0); Ball fixedBall = new Ball(250, 250, 20, 20); Rectangle mainBallRectangle = getMainBallBounds(); Rectangle fixedBallRectangle = getFixedBallBounds(); Thread updateTime = new updateTime(); public void start() { lastUpdateTime = System.currentTimeMillis(); Thread th = new Thread(this); th.start();//start main game updateTime.start(); } public void updateGame() { //Get the current time long currentTime = System.currentTimeMillis(); //Calculate how much time has passed since the last update long elapsedTime = currentTime - lastUpdateTime; //Store this as the most recent update time lastUpdateTime = currentTime; //Create a new dot if enough time has passed //Update the time since last new dot was drawn timeSinceLastNewDot += elapsedTime; if (timeSinceLastNewDot >= NEW_DOT_FREQ) { int newX = randomNumber(); int newY = randomNumber(); debugPrint("New dot created at x:" + newX + ", y:" + newY + "."); BALLS.add(new Ball(newX, newY, 20, 20)); timeSinceLastNewDot = 0; } } private void debugPrint(String value) { System.out.println(value); } public class updateTime extends Thread implements Runnable { public void run() { for(t = 0; ; t++) { try { Thread.sleep(1000); } catch(InterruptedException e){} } } } public int randomNumber() { return (int)(Math.random() * 400); } public int getRandomColor() { return (int)(Math.random() * 6); } public class MainBall { int width; int height; int xpos; int ypos; int xspeed; int yspeed; public MainBall( int xpos, int ypos, int width, int height, int xspeed, int yspeed) { this.width = 10; this.height = 10; this.xpos = 100; this.ypos = 100; this.xspeed = 0; this.yspeed = 0; } public void paintMainBall(Graphics g) { g.setColor(Color.black); g.fillOval(mainBall.xpos, mainBall.ypos, width, height); g.drawString(xpos + ", " + ypos, 20, 40); } }//mainBall class Ball { int x; int y; int width; int height; public Ball(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; }//end ball public void paint(Graphics g) { g.setColor(color[getRandomColor()]); g.fillOval(x, y, width, height); } //end paint } //ball class public void update(Graphics g) //double buffer don't touch!! { if(dbImage == null) { dbImage = createImage(this.getSize().width, this.getSize().height); dbg = dbImage.getGraphics(); } dbg.setColor(getBackground()); dbg.fillRect(0, 0, this.getSize().width, this.getSize().height); dbg.setColor(getForeground()); paint(dbg); g.drawImage(dbImage, 0, 0, this); } public boolean keyDown (Event e, int key) { if(key == Event.LEFT) { mainBall.xspeed = -5; mainBall.yspeed = 0; } if(key == Event.RIGHT) { mainBall.xspeed = 5; mainBall.yspeed = 0; } if(key == Event.UP) { mainBall.yspeed = -5; mainBall.xspeed = 0; } if(key == Event.DOWN) { mainBall.yspeed = 5; mainBall.xspeed = 0; } return true; } public void run() { while(true) { repaint(); if (mainBall.xpos < 1) { mainBall.xpos = 449; } if (mainBall.xpos > 449) { mainBall.xpos = 1; } if (mainBall.ypos < 1) { mainBall.ypos = 449; } if (mainBall.ypos > 449) { mainBall.ypos = 1; } mainBall.ypos += mainBall.yspeed; mainBall.xpos += mainBall.xspeed; try { Thread.sleep(20); } catch(InterruptedException ex){} } } public void init() { this.setSize(WIDTH, HEIGHT); BALLS = new ArrayList<Ball>(); System.out.println(getFixedBallBounds()); } public void paint(Graphics g) { g.drawString("time: " + t, 20, 20); mainBall.paintMainBall(g); g.setColor(Color.blue); fixedBall.paint(g); for (Ball ball : BALLS) { ball.paint(g); } updateGame(); } public Rectangle getFixedBallBounds() { return new Rectangle (250, 250, 20, 20); } public Rectangle getMainBallBounds() { return new Rectangle(mainBall.xpos, mainBall.ypos, 10, 10); } public boolean checkCollision() { if(mainBallRectangle.intersects(fixedBallRectangle)) { mainBall.xspeed = 0; mainBall.yspeed = 0; mainBall.xpos = 100; mainBall.ypos = 100; } return true; }}[/source]
#106 Members - Reputation: 508
Posted 12 August 2012 - 09:10 PM
In game's paint method, I think you should move the updateGame() call to the beginning of the method instead of the end. Also, moving all of your game logic into updateGame will make this more straightforward. Right now you have some in updateGame and some in run.
#108 Members - Reputation: 508
Posted 12 August 2012 - 09:34 PM
You'll want to make sure that you do the checkCollision check (and setting the speed to 0), just before you update the mainBall position.
[source lang="java"]//Update mainBall RectanglemainBallRectangle = getMainBallBounds();//Check for collisionscheckCollision();//Update mainBall positionmainBall.ypos += mainBall.yspeed;mainBall.xpos += mainBall.xspeed;//Wrap mainBall positionif (mainBall.xpos < 1){}............[/source]
Now you have the collision code that will potentially set the speed to 0 right before the location is updated based on that speed.
#110 Members - Reputation: 508
Posted 12 August 2012 - 09:54 PM
I can say the first things I'll be looking at are where those two rectangles are getting set. The idea is to make sure they're being set when they have the legit information in them. Putting a breakpoint in the checkCollision method is also a good idea to confirm that intersects check is actually returning true like we expect it to. And after that to put breakpoints at the lines where the ball's position is actually updated (mainBall.xpos += mainBall.xspeed;) to confirm that it has the value I expect it to have. You should also take a look at those points. They seem like likely places for things to be going wrong to me.
It'll probably be tomorrow before I give any indepth look though. I'll take a look at the code for essentially the first step that I said because that one could be a quick one to notice. But since the others will take running and debugging code, I'll put those off in my tired state.
#111 Members - Reputation: 238
Posted 12 August 2012 - 09:58 PM
[source lang="java"]import java.applet.Applet;import java.awt.Color;import java.awt.Component;import java.awt.Event;import java.awt.Graphics;import java.awt.Image;import java.awt.Rectangle;import java.util.ArrayList;import java.util.concurrent.TimeUnit;public class game extends Applet implements Runnable{ static final int WIDTH = 450; //set screen height static final int HEIGHT = 450; // set screen width private Image dbImage; private Graphics dbg; public static long NEW_DOT_FREQ = TimeUnit.SECONDS.toMillis(3); public long lastUpdateTime; public long timeSinceLastNewDot; public ArrayList<Ball> BALLS; //arraylist to store balls Color[] color = {Color.red, Color.blue, Color.green, Color.yellow, Color.magenta, Color.black}; int colorIndex; static final int NUM_OF_BALLS = 4; int i; int t; MainBall mainBall = new MainBall(100, 100, 10, 10, 0, 0); Ball fixedBall = new Ball(250, 250, 20, 20); Rectangle mainBallRectangle = getMainBallBounds(); Rectangle fixedBallRectangle = getFixedBallBounds(); Thread updateTime = new updateTime(); public void start() { lastUpdateTime = System.currentTimeMillis(); Thread th = new Thread(this); th.start();//start main game updateTime.start(); } public void updateGame() { checkCollision(); //Get the current time long currentTime = System.currentTimeMillis(); //Calculate how much time has passed since the last update long elapsedTime = currentTime - lastUpdateTime; //Store this as the most recent update time lastUpdateTime = currentTime; //Create a new dot if enough time has passed //Update the time since last new dot was drawn timeSinceLastNewDot += elapsedTime; if (timeSinceLastNewDot >= NEW_DOT_FREQ) { int newX = randomNumber(); int newY = randomNumber(); debugPrint("New dot created at x:" + newX + ", y:" + newY + "."); BALLS.add(new Ball(newX, newY, 20, 20)); timeSinceLastNewDot = 0; } if (mainBall.xpos < 1) { mainBall.xpos = 449; } if (mainBall.xpos > 449) { mainBall.xpos = 1; } if (mainBall.ypos < 1) { mainBall.ypos = 449; } if (mainBall.ypos > 449) { mainBall.ypos = 1; } try { Thread.sleep(20); } catch(InterruptedException ex){} checkCollision(); mainBall.ypos += mainBall.yspeed; mainBall.xpos += mainBall.xspeed; } private void debugPrint(String value) { System.out.println(value); } public class updateTime extends Thread implements Runnable { public void run() { for(t = 0; ; t++) { try { Thread.sleep(1000); } catch(InterruptedException e){} } } } public int randomNumber() { return (int)(Math.random() * 400); } public int getRandomColor() { return (int)(Math.random() * 6); } public class MainBall { int width; int height; int xpos; int ypos; int xspeed; int yspeed; public MainBall( int xpos, int ypos, int width, int height, int xspeed, int yspeed) { this.width = 10; this.height = 10; this.xpos = 100; this.ypos = 100; this.xspeed = 0; this.yspeed = 0; } public void paintMainBall(Graphics g) { g.setColor(Color.black); g.fillOval(mainBall.xpos, mainBall.ypos, width, height); g.drawString(xpos + ", " + ypos, 20, 40); } }//mainBall class Ball { int x; int y; int width; int height; public Ball(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; }//end ball public void paint(Graphics g) { g.setColor(color[getRandomColor()]); g.fillOval(x, y, width, height); } //end paint } //ball class public void update(Graphics g) //double buffer don't touch!! { if(dbImage == null) { dbImage = createImage(this.getSize().width, this.getSize().height); dbg = dbImage.getGraphics(); } dbg.setColor(getBackground()); dbg.fillRect(0, 0, this.getSize().width, this.getSize().height); dbg.setColor(getForeground()); paint(dbg); g.drawImage(dbImage, 0, 0, this); } public boolean keyDown (Event e, int key) { if(key == Event.LEFT) { mainBall.xspeed = -5; mainBall.yspeed = 0; } if(key == Event.RIGHT) { mainBall.xspeed = 5; mainBall.yspeed = 0; } if(key == Event.UP) { mainBall.yspeed = -5; mainBall.xspeed = 0; } if(key == Event.DOWN) { mainBall.yspeed = 5; mainBall.xspeed = 0; } return true; } public void passThroughWalls() { } public void run() { while(true) { repaint(); } } public void init() { this.setSize(WIDTH, HEIGHT); BALLS = new ArrayList<Ball>(); System.out.println(getFixedBallBounds()); } public void paint(Graphics g) { updateGame(); g.drawString("time: " + t, 20, 20); mainBall.paintMainBall(g); g.setColor(Color.blue); fixedBall.paint(g); for (Ball ball : BALLS) { ball.paint(g); } } public Rectangle getFixedBallBounds() { return new Rectangle (250, 250, 20, 20); } public Rectangle getMainBallBounds() { return new Rectangle(mainBall.xpos, mainBall.ypos, 10, 10); } public void checkCollision() { if(mainBallRectangle.intersects(fixedBallRectangle)) { mainBall.xspeed = 0; mainBall.yspeed = 0; mainBall.xpos = 100; mainBall.ypos = 100; } }}[/source]
#112 Members - Reputation: 508
Posted 12 August 2012 - 10:02 PM
#114 Members - Reputation: 508
Posted 12 August 2012 - 10:08 PM
#115 Members - Reputation: 238
Posted 13 August 2012 - 03:16 PM
i have this in my ball class
[source lang="java"] public Rectangle getBallBounds() { for(Ball ball : BALLS) return new Rectangle() }[/source]
this should return a rectangle every time one is created i think? besides the return method not being finished. i dont know how to call the coordinates of a ball in the array
Changed it to this
[source lang="java"] public Rectangle getBallBounds() { for(int i = 0; i < BALLS.size(); i++) { return new Rectangle(BALLS(i).x, BALLS(i).y, 20, 20); } Rectangle ballRectangle = getBallBounds(); }[/source]
so i will increase when the arraylist BALLS increases. but for some reason its saying BALLS(int) isnt a method when i want to call the ArrayList BALLS
and now to this
[source lang="java"] public Rectangle getBallBounds() { for(int i = 0; i < BALLS.size(); i++) { return new Rectangle(BALLS.get(i).x, BALLS.get(i).y, 20, 20); } Rectangle ballRectangle = getBallBounds(); }[/source]
now its saying the type im returning isnt a rectangle?
alright try again...
[source lang="java"] public Rectangle getBallBounds() { for(int i = 0; i < BALLS.size(); i++) { new Rectangle(BALLS.get(i).x, BALLS.get(i).y, 20, 20); } return randomBallRectangle; }[/source]
i made an object in the main game class Rectangle randomBallRectangle = getBallBounds();
the compiler shows no errors until i run it then i get this:
java.lang.NullPointerException
at game.getBallBounds(game.java:290)
at game.<init>(game.java:38)
Edited by burnt_casadilla, 13 August 2012 - 04:57 PM.
#116 Members - Reputation: 508
Posted 13 August 2012 - 06:13 PM
You don't want a for loop here. The reason you don't goes back to a concept that we talked about earlier. This class is designed to represent 1 ball. That means inside the Ball class, you should pretend that the array of balls doesn't exist. Because this code is intended to represent 1 ball, it doesn't care if you stick it in an array or not to make your game work. Because you do want an array of balls for your game, that's why your game class is creating and managing an array of balls.
So this method inside the Ball class should be concerned with returning you the Rectangle that encloses "me".. "me" being the 1 and only ball that it knows or cares about. The fact that you have an array of Balls and need Rectangles for them all is something for the game class to deal with (again, because the game class does want this array of Balls so that it can accomplish what it wants for this game).
So for the first step, focus on getting this method returning the Rectangle around itself (the "me" I mentioned before).
And then for the second step, get a loop (somewhere in the game class because the Ball class doesn't and shouldn't care about the array) that goes through each of the Balls in the array and stores you a Rectangle for each one.
Note: Determining where step 2 goes should be made easier by the fact that we did some simplifying of things last night. In your game class, you should be adding code in one of relatively few places. In the init method if you just need it to happen once when you initially launch your game. In the updateGame method if it's related to updating things that change during your game. And in the paint method if this involves drawing things for your game.
#117 Members - Reputation: 238
Posted 13 August 2012 - 06:17 PM
this is called everytime the ball class is used?
can you explain why i should keep this in the ball class? why would it be any different if it was outside of the class?
im thinking i should put it in the updateGame method and in the if method after the new ball is created every three seconds
[source lang="java"] if (timeSinceLastNewDot >= NEW_DOT_FREQ) { int newX = randomNumber(); int newY = randomNumber(); debugPrint("New dot created at x:" + newX + ", y:" + newY + "."); BALLS.add(new Ball(newX, newY, 20, 20)); getBallBounds(); timeSinceLastNewDot = 0; }[/source]
so maybe something like this?
Edited by burnt_casadilla, 13 August 2012 - 06:20 PM.
#118 Members - Reputation: 508
Posted 13 August 2012 - 07:43 PM
can you explain why i should keep this in the ball class? why would it be any different if it was outside of the class?
Definitely. Good question. Inside the class, it allows you to have a ball object Ball myBall = new Ball(x, y, width, height); and be able to refer to that ball's rectangle without needing to know about or deal with any other balls, Rectangle boundary = myBall.getBallBounds();.
If I put it outside the class and I want to know the boundaries of any given ball, I'll need to provide this method with what ball I am talking about (something like Rectangle boundary = getBallBounds(myBall);). It would certainly not be wrong to do it that way. But I've noticed that generally if you're making a method from scratch, you've tended to make it with no parameters. So I was favoring the way your were already writing methods.
And another perk (but not a 'metric' you should be using to make decisions at this point) is if your next game was going to do something different but still be using balls, you could very well have this Ball class in its own file and use it for both this game and the next one. If you have getBallBounds(Ball ball) in this game class, that means if your next game needed that same functionality, you'd have to implement it again. But since it does make good sense that the ball would be able to provide you with its own bounds, having inside the class is logical and makes one less piece of functionality that you'd have to re-implement.
In this code, you call getBallBounds() so it's returning you a Rectangle object but you're not doing anything with it. So you're not using it right now nor are you saving it somewhere (in some variable) so you can pull it back up later to use.im thinking i should put it in the updateGame method and in the if method after the new ball is created every three seconds
...
so maybe something like this?
Your getBallBounds method is looking alright. You did pull up the x and y values from this particular ball. Why did you hardcode the width and height rather than pulling those values from this particular ball as well?
Edited by j-locke, 13 August 2012 - 07:45 PM.
#119 Members - Reputation: 238
Posted 13 August 2012 - 07:49 PM
thanks for the explanation
well in the code i listed it would be calling the method, but in the main game class i would create the object Rectangle randomBallRectangle = getBallBounds();
also for my next game im planning on making a "Snake" clone so ill keep in mind what methods and classes i can reuse
Edited by burnt_casadilla, 13 August 2012 - 07:50 PM.
#120 Members - Reputation: 508
Posted 13 August 2012 - 08:30 PM
well in the code i listed it would be calling the method, but in the main game class i would create the object Rectangle randomBallRectangle = getBallBounds();
Ah, ok. You may already know this (because I realize we're talking in kind of code short hand sometimes and it's just understood what code goes where) but in case not I'll bring it up now before it is an issue of confusion later.
When you call getBallBounds(), it will return you the Rectangle and store it in whatever variable you put on the left side of the equal sign. So if you call balls.get(i).getBallBounds(), it won't go find some matching piece of code to find out where to store the Rectangle that is returned. It will simply return it and then it will be forever lost. So the confusion i wanted to be sure to avoid is that calling getBallBounds() is useless unless you are using the returned Rectangle either by having it in a statement (such as if (playerRectangle.intersects(balls.get(i).getBallBounds()))) or storing it so you can use it later (such as randomBallRectangle = balls.get(i).getBallBounds()).
I like that the next planned project isn't overly complex. That small steps approach will have you making some bigger projects in a couple of months time and hopefully not feeling TOO overwhelmed as you didn't jump too far beyond your knowledge all at once.






