that really sucks ... i know how to make classes, objects, interfaces, loops etc . But everytime i try to make a unit or more than one, that is moving (when i select it) to the point where i click i get errors, errors and errors .... Why the hell theres nowhere a tutorial for that ?
My new class looks so atm :
class Unit {
int X;
int Y;
int Breite;
int Laenge;
int ID;
boolean ausgewaelht = false;
Unit() {
}
Unit(int x, int y, int breite, int laenge) {
}
void create(UnitContent function) {
function.form();
}
void move(float geschwindigkeit) {
if(isTriggerd(X,Y,Breite,Laenge) == true){
X = X+(int)geschwindigkeit;
if(X > width) {
X = 0;
}
}
}
void setXandY(int x , int y) {
X = x;
Y = y;
}
void setBreiteandLaenge(int breite, int laenge) {
Breite = breite;
Laenge = laenge;
}
void setID(int id) {
ID = id;
}
int getX() {
return X;
}
int getY() {
return Y;
}
int getBreite() {
return Breite;
}
int getLaenge() {
return Laenge;
}
int getID() {
return ID;
}
boolean isTriggerd(int x, int y, int breite, int laenge) {
if(mouseX > x && mouseX < x+breite && mouseY > y && mouseY < y+laenge ) {
return true;
}
else {
return false;
}
}
}
IS there something i forgot ?
And how do i display 10 or 50 units of them?
sorry for my bad english :) and thx for your help
Some friendly advice: your tone comes off sounding a bit demanding, and your description is very vague. You'll have much better luck if you try to make it easy for other people to help you.
Tell us exactly what errors you're getting.
Post an MCVE with enough code so we can run it, but not any code that isn't directly related to your problem.
Try breaking your problem down into small steps, and only ask one specific question at a time.
Check out the question checklist and make sure you've done everything on the list.
Why the hell theres nowhere a tutorial for that ?
Keep in mind that the people answering questions on Stack Overflow are doing so for free, in their spare time. The people developing Processing are doing so for free, in their spare time. Even so, there are a ton of tutorials on your problems. Have you tried searching on google?
Here is a tutorial that does exactly what you're looking for. These examples come with the Processing editor (go to File -> Examples). The reference is another great resource that you should check out.
All of that being said, I'll walk you through solving this problem, and hopefully how to solve other problems in the future.
Step 0: Break your problem down into smaller steps. This is the golden rule of programming. Whenever you're stuck, go back to this step. This step fuels the rest of the steps, and it should be the first, second, and third thing you do whenever you're stuck.
Step 1: Can you draw a single object? Don't worry about interaction or multiple objects or anything else, just draw a single object. Get that code working first.
Here's code that draws a single circle:
void setup(){
size(500, 500);
ellipseMode(CENTER);
}
void draw(){
background(0);
ellipse(100, 200, 50, 50);
}
Step 2: Can you encapsulate the information needed to draw the object in a class? Again, only worry about the next small step- don't worry about multiple shapes yet. Just get a class working for a single object. Here is how we might encapsulate the data for our circle:
Circle circle;
void setup() {
size(500, 500);
ellipseMode(CENTER);
circle = new Circle(100, 200, 50);
}
void draw() {
background(0);
circle.draw();
}
class Circle {
float x;
float y;
float r;
public Circle(float x, float y, float r) {
this.x = x;
this.y = y;
this.r = r;
}
void draw() {
ellipse(x, y, r, r);
}
}
If you have trouble on this step, then you can post something like this small example with a more specific question, and it'll be much easier to help you than if you post a section of your entire sketch without any specific errors.
Step 3: Can you add some simple user interaction logic to your circle class? Don't worry about clicking yet, just try to change the color of the circle when you move your mouse over it.
Circle circle;
void setup() {
size(500, 500);
ellipseMode(RADIUS);
circle = new Circle(100, 200, 50);
}
void draw() {
background(0);
circle.draw();
}
class Circle {
float x;
float y;
float r;
public Circle(float x, float y, float r) {
this.x = x;
this.y = y;
this.r = r;
}
void draw() {
if(dist(mouseX, mouseY, x, y) < r){
//mouse is inside circle
fill(0, 255, 0);
}
else{
//mouse is outside circle
fill(0, 0, 255);
}
ellipse(x, y, r, r);
}
}
By breaking your bigger problem down into these smaller steps, it becomes much easier to debug your code than if you try to write your entire sketch at one time.
Step 4: Can you improve your interaction code to detect a click? Can you move the circle when a drag is detected?
You should probably break those steps down even further, but for the sake keeping this post short(er), I've combined them into one:
Circle circle;
void setup() {
size(500, 500);
ellipseMode(RADIUS);
circle = new Circle(100, 200, 50);
}
void draw() {
background(0);
circle.draw();
}
class Circle {
float x;
float y;
float r;
public Circle(float x, float y, float r) {
this.x = x;
this.y = y;
this.r = r;
}
void draw() {
if(dist(mouseX, mouseY, x, y) < r){
//mouse is inside circle
if(mousePressed){
//mouse is being dragged
fill(255, 0, 0);
//move the circle to the mouse position
x = mouseX;
y = mouseY;
}
else{
//mouse is not clicked
fill(0, 255, 0);
}
}
else{
//mouse is outside circle
fill(0, 0, 255);
}
ellipse(x, y, r, r);
}
}
Step 5: Can you make it work for multiple objects? If you've done a good job of breaking your problem down into small steps and encapsulating your logic into a class, then this step becomes pretty easy.
ArrayList<Circle> circles = new ArrayList<Circle>();
void setup() {
size(500, 500);
ellipseMode(RADIUS);
for (int i = 0; i < 10; i++) {
circles.add(new Circle(random(width), random(height), random(10, 50)));
}
}
void draw() {
background(0);
for (Circle circle : circles) {
circle.draw();
}
}
class Circle {
float x;
float y;
float r;
public Circle(float x, float y, float r) {
this.x = x;
this.y = y;
this.r = r;
}
void draw() {
if (dist(mouseX, mouseY, x, y) < r) {
//mouse is inside circle
if (mousePressed) {
//mouse is being dragged
fill(255, 0, 0);
//move the circle to the mouse position
x = mouseX;
y = mouseY;
} else {
//mouse is not clicked
fill(0, 255, 0);
}
} else {
//mouse is outside circle
fill(0, 0, 255);
}
ellipse(x, y, r, r);
}
}
To summarize, you need to break your problem down into smaller steps and take on those steps one at a time. If you get stuck on a specific step (or if you don't understand one of the steps in my answer) then you can post a small example MCVE like my examples above, and ask a specific question.
Happy coding!
It really doesn't look like you have any graphical code except for some coordinates. In order to display something in Java you have to use a library that supports it like Swing or JavaFX. Here's a SO question that will give you some idea of what the differences are. Happy coding!
Related
It's basically a simple game, in that, when the mouse pointer is within the circle, it adds one to the score. I'm new to processing and tried to create this simple game.
Here's the code:
float dist;
float score;
float x;
float y;
float ran;
float a;
float b;
void setup(){
size(800,600);
background(0);
score = 0;
}
void draw(){
background(0);
text("score: "+score,600,20);
x = random(800);
y = random(600);
circle_(x,y);
if ( (abs(mouseX - x) <= 200) && (abs(mouseY - y) <= 200 )) { // algorithm for checking whether mouse inside the circle or not
score = score + 1;
}
}
void circle_(float x,float y){
delay(1000);
circle(x,y,50);
}
There are 2 problems here: first, you're checking 200 pixels where it should be 25 (as in 25 being half the diameter of the circle). But this is the easy one. The real issue is with the delay(1000); line.
That's the real pain.
It means that your program "sleeps" for about 1000/1001 seconds. While the mouse can go around the screen, this one just isn't listening. It's waiting.
You can track time in Processing with the millis() method. It gives you how many milliseconds have passed since you started running the sketch. I ninja coded you a couple lines to keep track of time and teleport the circle every 1 second. Here's the code:
float score;
float x;
float y;
int respawnCircle;
void setup() {
size(800, 600);
background(0);
score = 0;
}
void draw() {
background(0);
text("score: "+score, 600, 20);
if (millis() > respawnCircle) {
changeCircleCoordinates();
}
circle_(x, y);
if ((abs(mouseX - x) <= 25) && (abs(mouseY - y) <= 25 )) { // using 25 as it's half the circle's diameter
score = score + 1;
// if you want the circle to change place right when you get one point uncomment the next line
// changeCircleCoordinates();
}
}
void changeCircleCoordinates() {
respawnCircle = millis() + 1000;
x = random(800);
y = random(600);
}
void circle_(float x, float y) {
//delay(1000); // this is why your collision detection wasn't working: the program is sleeping for about 1000/1001 milliseconds... you have to be very lucky to be on target at just the right time
circle(x, y, 50);
}
Hope it helps. Have fun!
I want to create an ArrayList of ball objects, which should be in a loop until there are 100 pieces.
Now my problem: I must implement a function hitTest, so that when you click on a ball it gets removed. In the same position, there should appear two balls then, which go into a different direction. I included mousePressed and a private boolean but it doesn't work and I don't know why.
Can someone help me? I am so lost...
Here's my code so far:
Tab 1
ArrayList<Ball> balls;
void setup()
{
size(800,800);
balls = new ArrayList<Ball>();
for(int i = 0; i<100; i++)
{
drawBall();
}
}
void draw()
{
background(255);
//b.update();
for(int i= 0; i<balls.size(); i++)
{
balls.get(i).update();
}
}
void drawBall()
{
Ball b = new Ball();
balls.add(b);
}
void mousePressed()
{
for(int i = balls.size()-1; i>=0; i--)
Ball ball = balls.get (i);
if (ball.hitTest())
{
balls.get(i).hitTest();
balls.remove(ball);
Ball b1 = new Ball(mouseX, mouseY);
Ball b2 = new Ball(mouseX, mouseY);
balls.add(b1);
balls.add(b2);
}
}
/*Tab 2:*/
class Ball
{
private float x;
private float y;
private float ballSize;
private float dirX;
private float dirY;
private boolean moving = true;
Ball()
{
this.x = width/2;
this.y = height/2;
this.ballSize = random(10.0,30.0);
this.dirX = random(-3.0,3.0);
this.dirY = random(-3.0,3.0);
if(this.dirX<1.0 && this.dirX>1.0)//1 statt -1 macht zufälliger
{
this.dirX = 1.0;
}
if(this.dirY<1.0 && this.dirY>1.0)
{
this.dirY = 1.0;
}
}
public void update()
{
stroke(255);
fill(random(255),random(255),random(255), random(255));
ellipse( this.x, this.y, this.ballSize, this.ballSize);
if(this.moving == true)
{
this.x += this.dirX;
this.y += this.dirY;
}
if(this.x+ this.ballSize/2> width ||this.x- this.ballSize/2<0)
{
this.dirX= dirX*-1;
}
if(this.y+ this.ballSize/2> height ||this.y- this.ballSize/2<0)
{
this.dirY= dirY*-1;
}
}
private boolean hitTest()
{
float d = dist(this.x, this.y, mouseX, mouseY);
if (d < ballSize)
{
println("h");
return true;
}
else
{
return false;
}
}
}
You are very very close! Most of the code you posted is pretty much there.
There are a few syntax issues:
The instructions within the for loop in mousePressed() need to be enclosed:
This section here:
for(int i = balls.size()-1; i>=0; i--)
Ball ball = balls.get (i);
if (ball.hitTest())
{
balls.get(i).hitTest();
balls.remove(ball);
Ball b1 = new Ball(mouseX, mouseY);
Ball b2 = new Ball(mouseX, mouseY);
balls.add(b1);
balls.add(b2);
}
should be:
for(int i = balls.size()-1; i>=0; i--){
Ball ball = balls.get (i);
if (ball.hitTest())
{
balls.get(i).hitTest();
balls.remove(ball);
Ball b1 = new Ball(mouseX, mouseY);
Ball b2 = new Ball(mouseX, mouseY);
balls.add(b1);
balls.add(b2);
}
}
This part on it's own is valid syntax:
for(int i = balls.size()-1; i>=0; i--)
Ball ball = balls.get (i);
You can use a for loop without curly braces, but only if you plan to use a single instruction within the loop. In this case it's retrieving the Ball, which isn't very useful on it's own. Assuming you want to check the condition for each ball, that is a list of multiple instructions which need to be enclosed between {}.
(It's a shame Processing only displays this unhelpful error in particular case:
Consider adding "="
)
One other minor detail is the duplicate call to hitTest():
ball is the same as balls.get (i) in the context above, therefore calling balls.get(i).hitTest(); after calling ball.hitTest() is redundant. (also nothing is done with the boolean result it returns):
for(int i = balls.size()-1; i>=0; i--){
Ball ball = balls.get (i);
if (ball.hitTest())
{
balls.remove(ball);
Ball b1 = new Ball(mouseX, mouseY);
Ball b2 = new Ball(mouseX, mouseY);
balls.add(b1);
balls.add(b2);
}
}
Moving forward you would run into this error:
The constructor "Ball(int, int)" does not exist
The new Ball(mouseX, mouseY); constructor is called in mousePressed(), however your Ball class only supplies the default one with no arguments (e.g. Ball(), not Ball(x,y).)
You can easily copy/paste your existing constructor and modify it to add the x, y parameters:
Ball(float x, float y)
{
this.x = x;
this.y = y;
this.ballSize = random(10.0,30.0);
this.dirX = random(-3.0,3.0);
this.dirY = random(-3.0,3.0);
if(this.dirX<1.0 && this.dirX>1.0)//1 statt -1 macht zufälliger
{
this.dirX = 1.0;
}
if(this.dirY<1.0 && this.dirY>1.0)
{
this.dirY = 1.0;
}
}
Another option, avoiding duplicated code (which is not recommended) is to call the first constructor:
Ball(float x, float y){
this();// this() calls Ball()
this.x = x;
this.y = y;
}
Full code listing:
ArrayList<Ball> balls;
void setup()
{
size(800,800);
balls = new ArrayList<Ball>();
for(int i = 0; i<100; i++)
{
drawBall();
}
}
void draw()
{
background(255);
//b.update();
for(int i= 0; i<balls.size(); i++)
{
balls.get(i).update();
}
}
void drawBall()
{
Ball b = new Ball();
balls.add(b);
}
void mousePressed()
{
for(int i = balls.size()-1; i>=0; i--){
Ball ball = balls.get (i);
if (ball.hitTest())
{
balls.remove(ball);
Ball b1 = new Ball(mouseX, mouseY);
Ball b2 = new Ball(mouseX, mouseY);
balls.add(b1);
balls.add(b2);
}
}
}
/*Tab 2:*/
class Ball
{
private float x;
private float y;
private float ballSize;
private float dirX;
private float dirY;
private boolean moving = true;
Ball()
{
this.x = width/2;
this.y = height/2;
this.ballSize = random(10.0,30.0);
this.dirX = random(-3.0,3.0);
this.dirY = random(-3.0,3.0);
if(this.dirX<1.0 && this.dirX>1.0)//1 statt -1 macht zufälliger
{
this.dirX = 1.0;
}
if(this.dirY<1.0 && this.dirY>1.0)
{
this.dirY = 1.0;
}
}
Ball(float x, float y){
this();
this.x = x;
this.y = y;
}
public void update()
{
stroke(255);
fill(random(255),random(255),random(255), random(255));
ellipse( this.x, this.y, this.ballSize, this.ballSize);
if(this.moving == true)
{
this.x += this.dirX;
this.y += this.dirY;
}
if(this.x+ this.ballSize/2> width ||this.x- this.ballSize/2<0)
{
this.dirX= dirX*-1;
}
if(this.y+ this.ballSize/2> height ||this.y- this.ballSize/2<0)
{
this.dirY= dirY*-1;
}
}
private boolean hitTest()
{
float d = dist(this.x, this.y, mouseX, mouseY);
if (d < ballSize)
{
println("h");
return true;
}
else
{
return false;
}
}
}
I've noticed hitTest() is using this condition:
if (d < ballSize)
ballSize is used here: ellipse( this.x, this.y, this.ballSize, this.ballSize);
which means it's the diameter. Normally for a circle hit test you'd check if the distance is smaller than the radius, not the diameter. Perhaps this is not a bug, but a feature :) ? Allowing for twice the size for easier clicks outside the ball area ?
One other minor suggestion: if you don't want the colours to randomly change multiple times a second, you can create a color property to store the random colour once in the Ball constructor, then simply reference that set colour in update()
You've got most of the tasks done. Remember to take it easy, re-read the code after a break and picture how it would run in your head before running it. It might help find issues like these. It may seem counterintuitive to slow down, but doing so and paying attention to detail will actually speed you up on the long run. Good luck
A small change which could make all the difference would be to add a constructor. Constructors can call one another and have different parameters, so each overload can have small differences.
The best way to write these isn't to copy-and-paste your constructor but to write them in a cascade which avoids making twice the same operation.
As an example, here you could use 2 constructors: one which just creates a ball, and one which creates a ball with specific coordinates. Their signatures would be like this:
Ball() // this one creates a ball with pre-choosen coordinates
Ball(float x, float y) // this one creates a ball at these coordinates
In a cascade, always try to keep your signature the same and add stuff, by which I mean do it like this (this is a completely fictive class):
// a correct way to cascade constructors
MyClass()
MyClass(int a, int b)
MyClass(int a, int b, boolean c)
MyClass(int a, int b, boolean c, String d)
Now, there is a prefered order in which you can place your parameters, but I won't go into this as most of the time devs adds them when they need them. The important thing is to avoid doing this:
// a bad way to cascade constructors
MyClass()
MyClass(int a, int b)
MyClass(String d)
MyClass(int a, boolean c, int b)
// etc
I'm saying this because you want the constructors in your cascade to call one another in an orderly manner which won't multiply manipulations. You don't want a constructor to set some coordinates only for another one to set different values to these same variables!
Of course, there can be a good reason to create a constructor like the one that just takes a String as parameter, but when you will have a situation which calls for this kind of modification, you'll have to think it through so your constructors keep some kind of internal logic. You don't want to spaghetti your constructors, that would be worse than having only one constructor which would be very complicated.
To continue with the example, here is how these constructors could call one another:
// a correct way to cascade constructors
MyClass() {
this(0, 0); // a constructor can call another one by using the keyword 'this'
}
MyClass(int a, int b) {
this(a, b, true); // keep it simple: the constructors inside the cascade typically just pass the parameters to more complex constructors
}
MyClass(int a, int b, boolean c) {
this(a, b, c, "defaultName"); // every ignored value is set to their "default value"
}
MyClass(int a, int b, boolean c, String d) {
// at last, the "real" constructor, which will do most of the work
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
Notice that, in the last example, if you call the MyClass() constructor, every parameter of the "real" constructor - the most complex one - will be a default value.
So... to come back to your specific situation, we have a cascade with only 2 different signatures:
Ball()
Ball(float x, float y)
So, to reproduce the logic I just laid out, you could modify your code like this:
Ball() {
// this constructor will produce balls just like you're used to
// I just moved the x/y assignation here
this(width/2, height/2);
}
Ball(float x, float y) {
// this is your "most complex constructor", you can use it to spawn a ball with custom coordinates
this.x = x;
this.y = y;
this.ballSize = random(10.0, 30.0);
this.dirX = random(-3.0, 3.0);
this.dirY = random(-3.0, 3.0);
if (this.dirX<1.0 && this.dirX>1.0)//1 statt -1 macht zufälliger
{
this.dirX = 1.0;
}
if (this.dirY<1.0 && this.dirY>1.0)
{
this.dirY = 1.0;
}
}
Please be careful and considerate when you add a constructor. Always reflect on what you're doing, as many constructors serves no purpose but to clutter the program - for now you probably won't notice this side effect, but keep it in mind for when you'll work on bigger projects, especially with teammates or at work. Projects which development and support lasts for years (like real programs) have a tendency to gather a lot of clutter, especially when devs make "small changes" all the time without regard for the structure of the program.
Have fun!
I am currently working on a 3 cushion billiards game project. I have added two balls on the table so far. I am trying to move one of the balls but I am having a hard time doing that. Should I use a timer? If so then could you tell me an effective way to use the timer on my code so I can move my balls?
Your help would be much appreciated.
Thanks in advance.
Farhan Hasan
I have tried to create a move function for the class balls. But I am not sure what I should put inside the function, I have added the xSpeed and ySpeed. The xLocation and the yLocation changes depending on the xSpeed and ySpeed.
public class Balls
{
private Color ballFillColor;
private Color ballBorderColor;
private int ballX = 0;
private int ballY = 0;
private int xSpeed = 5;
private int ySpeed = 0;
private int ballWidth = 0;
private int ballHeight = 0;
Timer t;
public boolean fillBall = false;
private static Balls ballArray[]; //Required for drawMultipleBalls
Balls(){ //Constructor
ballBorderColor = Color.black;
}
Balls(int ballX, int ballY, int ballWidth, int ballHeight, Color ballBorderColor, JFrame window){ //Constructor
// X , Y , Width, Height, Border Colour, container
this.setBallBorderColor(ballBorderColor);
this.setBallWidth(ballWidth);
this.setBallHeight(ballHeight);
this.setBallX(ballX);
this.setBallY(ballY);
this.drawBall(window);
}
//Here is the move function. I am not really sure what to do here.
public void move()
{
if(this.ballX < 1000 - this.ballWidth)
{
this.ballX += this.xSpeed;
}
try
{
Thread.sleep(1);
}
catch(Exception e)
{
}
}
//GET AND SET FUNCTIONS HERE
//HERE ARE THE FUNCTIONS WHICH ARE RESPONSIBLE FOR DRAWING MY BALLS IN JFRAME
public void drawBall(JFrame frame)
{
frame.getContentPane().add(new MyComponent());
}
public void drawMultipleBalls(JFrame frame, Balls[] balls)
{
ballArray = balls;
frame.getContentPane().add(new MyComponent2());
}
private class MyComponent extends JComponent{
public void paintComponent(Graphics g){
if (fillBall) //Fill first, and then draw outline.
{
g.setColor(ballFillColor);
g.fillOval(getBallX(),getBallY(), getBallHeight(),getBallWidth());
}
g.setColor(getBallBorderColor());
g.drawOval(getBallX(),getBallY(), getBallHeight(),getBallWidth());
}
}
private class MyComponent2 extends JComponent{
public void paintComponent(Graphics g){
for (int i = 0; i < ballArray.length; i++)
{
if (ballArray[i].fillBall) //Fill first, and then draw outline.
{
g.setColor(ballArray[i].ballFillColor);
g.fillOval(ballArray[i].getBallX(),ballArray[i].getBallY(), ballArray[i].getBallHeight(),ballArray[i].getBallWidth());
}
g.setColor(ballArray[i].getBallBorderColor());
g.drawOval(ballArray[i].getBallX(),ballArray[i].getBallY(), ballArray[i].getBallHeight(),ballArray[i].getBallWidth());
}
}
}
Hopefully, I can have two movable balls for the game, the should bounce back as the hit the edge of the screen and they should be able to slow down over time. For that, I am thinking to use a damper (I will multiply the xSpeed and ySpeed with a number less than 1, eventually it will slow down the ball)
Here is a simple example I came up with to show a ball moving and bouncing off the edges.
The direction changes based on the boundary. Left and top edges just check for 0. Bottom and right edges need to include the diameter of the ball.
The x and y increments are independent. And these amounts in conjunction with the timer can change the movement. Notice however, that to have objects bounce off of each other (as in a pool game) is more complicated due to angle of trajectories, etc. And the distances bounced will vary and slow with time based on frictional values. Everything else is documented in the Java API.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MovementDemo extends JPanel implements ActionListener {
JFrame frame = new JFrame("Movement Demo");
int size = 500;
int x = 50;
int y = 200;
int diameter = 50;
int yinc = 2;
int xinc = 2;
int xdirection = 1;
int ydirection = 1;
public MovementDemo() {
setPreferredSize(new Dimension(size, size));
frame.add(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new MovementDemo().start());
}
public void start() {
Timer timer = new Timer(100, this);
timer.setDelay(5);
timer.start();
}
public void actionPerformed(ActionEvent ae) {
if (x < 0) {
xdirection = 1;
}
else if (x > size - diameter) {
xdirection = -1;
}
if (y < 0) {
ydirection = 1;
}
else if (y > size - diameter) {
ydirection = -1;
}
x = x + xdirection * xinc;
y = y + ydirection * yinc;
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.BLUE);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(x, y, diameter, diameter);
}
}
It seems in general there are a few things you need to figure out:
has the ball collided with another ball
has the ball collided with a wall
otherwise just figure out what is the ball's new position based on its velocity
Below is some sample code that stubs some of this out. You can first compare the current ball's position to all others (not including the current ball of course). If there are any equal positions, process a collision with a ball. If the ball is at the window border i.e it hit a wall, process a collision with a wall. Otherwise just calculate its new position based on its current velocity.
The process collision part is just to apply physics mechanics to whatever degree of complexity you require. One general suggested change would be to update the velocity of the balls then apply it to the position after. The specific calculations for velocity changes you could apply as needed and as you can imagine it can get pretty involved which is why I suggest using a separate method and possibly a sub class for velocity instead of managing each part of the velocity vector in the ball itself. I used the wall as an object because of this. The composition, weights, velocities etc of the object's colliding can affect the resulting collision, but how complex you want that processing to be is up to you.
Sorry I'm no physics expert but I hope this sends you in the right direction in terms of code! Also this might help with the specific calculations you might want to use:
https://www.khanacademy.org/science/physics/one-dimensional-motion/displacement-velocity-time/v/calculating-average-velocity-or-speed
public void move()
{
// check if balls are on same position not including this ball
for(Ball b: ballArray){
if (this.position == b.position && this != b){
processCollision(this, b, null);
} else{
// if the ball hasn't collided with anything process its movement based on speed
// this assumes a 1000 x 1000 window for keeping objects inside it
if(this.ballX < 1000 - this.ballWidth && this.ballY < 1000 - this.ballHeight){
this.ballX += this.xSpeed;
this.ballY += this.ySpeed;
}else {
processCollision(this, null, new Wall());
}
}
}
try
{
Thread.sleep(1);
}
catch(Exception e)
{
}
}
public void processCollision(Ball b1, Ball b2, Wall w){
// if ball hasn't collided with a wall, process a ball - ball collision
if(w == null){
// apply physics mechanics according the complexity desired for ball collisions
b1.xSpeed -= b2.xSpeed;
b1.ySpeed -= b2.ySpeed;
// ball 2 would end up slowing down
b2.xSpeed -= b1.xSpeed;
b2.ySpeed -= b1.ySpeed;
}
// if ball hasn't collided with a ball, process a ball - wall collision
if(b2 == null){
// apply physics mechanics for hitting a wall
// e.g as below: just send ball in opposite direction
b1.xSpeed = b1.xSpeed * -1;
b1.ySpeed = b1.ySpeed * -1;
}
// either way, process ball's new position based on its new speed
b1.ballX += b1.xSpeed;
b1.ballY += b1.ySpeed;
b2.ballX += b2.xSpeed;
b2.ballY += b2.ySpeed;
}
I am trying to change the y position of the rectangle, however, whenever I try to, it expands/gets bigger vertically.
public class PlayerPaddle implements Paddle {
double yVelocity;
final double GRAVITY = 0.94;
//move up/down faster (if not accelerating = slow down)
boolean upAccel, downAccel;
//determines if player 1 or player 2 (on left or on right)
int player;
//position of actual paddle
int x;
double y;
Rectangle panel;
public PlayerPaddle(int player) {
upAccel = false;
downAccel = false;
y = 210; //not moving initially
yVelocity = 0;
if (player == 1) {
//left side
x = 20;
} else {
//right side
x = 660;
}
}
#Override
public void draw(Graphics g) {
//draw paddle
g.setColor(Color.WHITE);
g.fillRect(x, (int) y, 20, 80);
}
#Override
public void move() {
if (upAccel) {
yVelocity -= 2;
} else if (downAccel) {
yVelocity += 2;
} else if ((!upAccel) && (!downAccel)) {
yVelocity *= GRAVITY;
}
y += yVelocity; //changes y position of paddle
}
public void setUpAccel(boolean input) {
upAccel = input;
}
public void setDownAccel(boolean input) {
downAccel = input;
}
#Override
public int getY() {
return (int) y;
}
}
I want to know how to make the rectangle move up and down vertically. A similar question had only one answer which said that the previously painted rectangle was not being cleared and as a result is expanding. But even when I say g.clearRect(...) it still expands and does not move.
I am new to Swing and Awt but I am really committed to learning. Thanks for the help.
A similar question had only one answer which said that the previously painted rectangle was not being cleared and as a result is expanding
And that is still probably the problem here.
Somewhere, not in the code presented here, you need to invoke the draw(...) method of this class.
So in that code you need to make sure the background of the component is cleared before you draw the paddle. Since you should be overriding the paintComponent(...) method of a panel to do custom painting your code should look something like:
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
// draw the paddle
}
Read the section from the Swing tutorial on Custom Painting for more information and working examples.
I am new to Swing and Awt but I am really committed to learning.
Then keep a link to the tutorial handy for all Swing basics.
I'm making a game where you're controlling a square, and objects will spawn in random places, which you have to pick up to get points, while also having to dodge big squares going from side to side. Right now I have 2 classes (one for enemies - big squares -, and one for the hero), I haven't done the point system yet with the spawning objects, but that's not what I'm trying to do now.
So my problem right now is that I don't really know how to make the person lose the game/a life when you touch the "enemies" with your hero. I would know how to do it without classes, but I'd like to know how to do it when they are in separate classes.
If someone could explain with code and comments how this would be done, it would help me out a lot :) (I read something about 'extends' for classes but I'm not sure if this is what I should use or not).
Here's a screenshot of what my game looks like at the moment, just to better illustrate it:
Here's the main code page:
Hero myHero = new Hero(400,480,5);
Enemies myEnemies = new Enemies(50,50,10);
Enemies myEnemies2 = new Enemies(50,350,15);
Enemies myEnemies3 = new Enemies(50,650,12);
void setup() {
size(900,800);
frameRate(30);
smooth();
}
void draw() {
background(0);
myHero.keyPressed();
myEnemies.enemyDisplay();
myEnemies.enemyMove();
myEnemies2.enemyDisplay();
myEnemies2.enemyMove();
myEnemies3.enemyDisplay();
myEnemies3.enemyMove();
}
Class 1:
class Enemies {
float xpos, ypos, speed;
Enemies(float x, float y, float s) {
xpos = x;
ypos = y;
speed = s;
}
void enemyDisplay() {
rect(xpos, ypos, 100, 100);
}
void enemyMove() {
xpos += speed;
if((xpos > width - 100) || (xpos < 0)) {
speed *= -1;
}
}
}
Class 2:
class Hero {
float xpos_, ypos_, speed_;
Hero(float x, float y, float s) {
xpos_ = x;
ypos_ = y;
speed_ = s;
}
void keyPressed() {
if (key == CODED) {
if (keyCode == UP) {
ypos_ -= speed_;
}
if (keyCode == DOWN) {
ypos_ += speed_;
}
if (keyCode == LEFT) {
xpos_ -= speed_;
}
if (keyCode == RIGHT) {
xpos_ += speed_;
}
}
rect(xpos_,ypos_,30,30);
}
}
I believe the question you are asking involves basic collision detection and object interactions.
I would first make the Enemies a List and create it / add elements during the setup() call:
List<Enemies> enemies = new List<Enemies>();
enemies.add(new Enemies(50,50,10));
This allows you to store all of your Enemies under one object. So your draw() method would look something like:
void draw(){
background(0);
myHero.keyPressed();
for(Enemies enemy : enemies)
{
enemy.enemyDisplay();
enemy.enemyMove();
if (hero.isCollidingWith(enemy)) // collision method defined in the hero object, but you could define it in the Enemies class as well, it doesn't really matter
{
hero.removeHealth(); // method defined in hero that removes health
}
}
}
This method would be in one of your classes:
public boolean isColliding(Enemies enemy)
{
// check the x and y coordinates of each object
}
I hope this helps to point you in the right direction.
you need to figure out collision detection and when your objects collide with each other, something basic like:
class Enemy
{
//...
public boolean isColliding(Hero hero)
{
//figure out the distance between two objects, if its less than their size, they are colliding..
//...
}
//...
}
then you need a part of your Game Loop that checks if anything is colliding with your hero, pickups, walls, etc...
It seems the first part you need help with is collision detection. The short answer I would give that will almost undoubtedly lead you to more questions is to look at the Area class (specifically Area.intersect). You might also want to look at the classes I've put together for displaying & managing areas in this project here
There are several problems here that touch on both application design as well as conventions. These should be addressed first before trying to tackle the collision detection problem.
The Enemies class only represents a single enemy, so the name of the class should reflect that. Additionally, prefixing the method names with "enemy" is redundant and can be removed. Other changes have been commented in the revised class below.
public class Enemy {
// Instead of hard-coding in the width and height of an enemy, allow the
// instantiating code to specify the enemy's size. This will allow you
// to have different size enemies and prevents you from having "magic numbers"
// in your code.
private float xpos, ypos, width, height, speed;
public Enemy(float x, float y, float s, float w, float h) {
xpos = x;
ypos = y;
width = w;
height = h;
speed = s;
}
/* These getters will be used for collision detection later */
public float getX() {
return xpos;
}
public float getY() {
return ypos;
}
public float getWidth() {
return width;
}
public float getHeight() {
return height;
}
// I've changed `display` to `draw` to be consistent with the method name in
// your main `draw` method.
public void draw() {
rect(xpos, ypos, width, height);
}
// This method now accepts a screenWidth parameter so that the enemy can know
// when they've collided with the left or right wall of the screen without
// having to rely on an global variable.
public void move(int screenWidth) {
xpos += speed;
if ((xpos > screenWidth - width) || (xpos < 0)) {
speed *= -1;
}
}
}
I mention the "magic numbers" in one of the comments above. See this wikipedia article for more on that.
The Hero class contains property names that have an underscore postfix. This ranges from unconventional to inconsistent with respect to all of your other property names in your other classes. The original keyPressed() method mixes the logic for both drawing and moving. These two things have been separated and the methods named like those of the Enemy class for consistency.
public class Hero {
private float xpos, ypos, width, height, speed;
public Hero(float x, float y, float s, float w, float h) {
xpos = x;
ypos = y;
width = w;
height = h;
speed = s;
}
// Change this method name to draw for consistency with the Enemy class
public void draw() {
// Key press functionality has been moved to the `move` method for consistency
// with the Enemy class.
rect(xpos, ypos, WIDTH, HEIGHT);
}
// This method uses the variables key, keyCoded, UP, DOWN, LEFT, and RIGHT. You
// did not include any import statements with your code, so they may be coming
// from there; however, if they are globals, you should pass them to this method
// as arguments whenever you call it.
public void move() {
// If this condition isn't satisfied, return immediately. This prevents
// unnecessary nesting and work below.
if (key != CODED) {
return;
}
if (keyCode == UP) {
ypos -= speed;
}
// Use `else if` here and below to prevent multiple unnecessary
// comparisons of keyCode.
else if (keyCode == DOWN) {
ypos += speed;
}
else if (keyCode == LEFT) {
xpos -= speed;
}
else if (keyCode == RIGHT) {
xpos += speed;
}
}
public boolean isColliding(Enemy enemy) {
// Collision detection is easy since all of your game entities (the hero and
// the enemies) are all rectangles and axis-aligned (not rotated). You can
// use a method known as "bounding box intersection."
return (Math.abs(enemy.getX() - xpos) * 2 < (enemy.getWidth() + width))
&& (Math.abs(enemy.getY() - ypos) * 2 < (enemy.getHeight() + height));
}
}
For more on bounding box intersection, see this gamedev stackexchange question.
Now that your classes are in order, its time to address your main code. We'll need to update the method names and, as #James T suggested, you should make a list of enemies instead of creating a new independent object for each enemy. This will make it easier for you to add or remove enemies in the future and to be able to process all enemies with one block of code without repeating yourself.
// Use constants to remove magic numbers.
private static final int SCREEN_WIDTH = 900;
private static final int SCREEN_HEIGHT = 800;
private Hero myHero = new Hero(400, 480, 30, 30, 5);
private List<Enemy> enemies = new ArrayList<Enemy>();
void setup() {
size(SCREEN_WIDTH, SCREEN_HEIGHT);
frameRate(30);
smooth();
enemies.add(new Enemy(50, 50, 100, 100, 10));
enemies.add(new Enemy(50, 350, 100, 100, 15));
enemies.add(new Enemy(50, 650, 100, 100, 12));
}
void draw() {
hasCollision = false;
background(0);
// I've changed the order of draw->move to move->draw. If you draw first, then
// move, then detect collisions, it will appear to your user that your hero has
// not yet collided with an enemy even though you act as they have (e.g.: they
// will not see the collision until the next time you draw the scene).
myHero.move();
myHero.draw();
for (Enemy enemy : enemies) {
enemy.move();
enemy.draw(SCREEN_WIDTH);
if (!hasCollision && myHero.isColliding(enemy)) {
hasCollision = true;
}
}
if (hasCollision) {
// Handle enemy collision here
}
}
You'll notice that I've also added accessibility modifiers to everything. While it is technically valid to exclude them and use the defaults, it makes your code more readable to include them because it is more obvious. When you're first starting out, the more obvious the better.
Alright got it to work thanks to all you helpful wonderful people!
I did this:
public boolean isColliding(Enemies h){
float distance = dist(x,y,h.x,h.y);
if(distance<100){
return true;
}else{
return false;
}
}
and in my draw(){ I have
if(myHero.isColliding(myEnemies)){
println("You lost!");
}
I had a very similar 'fix' earlier, but the reason I got an error was because I had Hero h instead of Enemies h in the 'if' function, so it was just a very dumb error that I overlooked :P