I have started a Snake game for a University project and I am currently having an issue where the first segment of the body stored in an array is in the same location as the head. I don't quite know how I would go about offsetting the position of the first segment of the body so it isn't in the same position as the head part.
I noticed this when I was creating collision detection between the body and the head and it wasn't working as the first segment was in the same position as the head.
MainApp.java
import processing.core.*;
import java.awt.*;
/**
* Created by Wills on 25/05/2018.
*/
public class MainApp extends PApplet{
Snake snake;
Food food;
public static void main(String[] args){
PApplet.main("MainApp", args);
}
int screenSize = 800;
int scale = 20;
public void settings(){
size(screenSize,screenSize);
snake = new Snake(width/2, height/2, 0, 1, scale, screenSize );
food = new Food(screenSize, scale);
}
public void setup(){
frameRate(10);
rect(food.getX(), food.getY(), scale, scale);
}
public void draw() {
background(0);
snake.update();
fill(255);
rect(snake.getX(), snake.getY(), snake.getScale(), snake.getScale());
if(snake.getX() == food.getX() && snake.getY() == food.getY()){
snake.eat();
}
for(Point p: snake.getBody()){
if(food.getX() == p.getX() && food.getY() == p.getY()){
food.rePos();
}
rect((float)p.getX(), (float)p.getY(), snake.getScale(), snake.getScale());
}
fill(255,0,0);
rect(food.getX(), food.getY(), scale, scale);
}
public void mouseClicked(){
snake.eat();
snake.eat();
snake.eat();
snake.eat();
}
public void keyPressed(){
if(key == 'a'){
snake.setDirection(-1, 0);
}
if(key == 'd'){
snake.setDirection(1, 0);
}
if(key == 'w'){
snake.setDirection(0, -1);
}
if(key == 's'){
snake.setDirection(0, 1);
}
}
}
Snake.java
import processing.core.PApplet;
import java.awt.*;
import java.util.ArrayList;
/**
* Created by Wills on 25/05/2018.
*/
public class Snake extends PApplet{
int x, y, yspeed, xspeed, scale;
int score;
int screenSize;
ArrayList<Point> body;
public Snake(int x, int y, int xspeed, int yspeed, int scale, int screenSize){
body = new ArrayList<Point>();
this.x = x;
this.y = y;
this.xspeed = xspeed;
this.yspeed = yspeed;
this.scale = scale;
this.screenSize = screenSize;
}
public int getX(){
return x;
}
public int getY() {
return y;
}
public void setDirection(int x, int y){
this.xspeed = x;
this.yspeed = y;
}
public float getScale(){
return scale;
}
void update(){
x = constrain(x + xspeed * scale,0, screenSize - scale);
y =constrain(y + yspeed * scale,0, screenSize - scale);
body.add(0, new Point(x, y));
body.remove(score);
}
void eat(){
body.add(new Point(x,y));
score ++;
System.out.println(score);
}
void kill(){
score = 0;
x = screenSize/2;
y = screenSize/2;
}
ArrayList<Point> getBody(){
return body;
}
}
Food.java
import processing.core.PApplet;
import java.awt.*;
import java.util.ArrayList;
/**
* Created by Wills on 25/05/2018.
*/
public class Food extends PApplet{
float screenSize;
int scale, x, y;
Food(int screenSize, int scale){
this.scale = scale;
this.screenSize = screenSize;
generate();
}
float getX(){
return x;
}
float getY(){
return y;
}
public void rePos() {
generate();
}
private void generate(){
x = floor(random(0, scale));
y = floor(random(0, scale));
x = (int) map(x, 0, scale, 0, screenSize);
y = (int) map(y, 0, scale, 0, screenSize);
}
}
Any help would be much appreciated!
Related
I am trying to make a simple screen-saver, and I think I have everything else implemented properly. I just don't know how to make the shapes move. Looking at the code a bit more, I think it has something to do with the way I might have implemented the shapes themselves (the if (line), etc.)? I have looked at other answers regarding this question, but I couldn't quite find the answer I was looking for with the way my code is implemented. Any advice is super helpful, thank you!
Also, just for a side note, is the -40 necessary for the "if" conditions? I thought I heard somewhere that it is useful to leave a little space in-between the frame, but I can't remember why.
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
public class MyScreenSaver extends JComponent
{
ArrayList <Shapes> randomShapes = new ArrayList <>();
Shapes randomShape;
public MyScreenSaver ()
{
class TimerListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent event)
{
// Create random generation of colors and shapes...
Shape shape = null;
int frameWidth = 800;
int frameHeight = 500;
for (int i = 1; i <= 10; i ++)
{
Random rng = new Random();
boolean line = rng.nextBoolean();
boolean rectangle = rng.nextBoolean();
int red = ((int) (Math.random() * 255));
int green = ((int) (Math.random() * 255));
int blue = ((int) (Math.random() * 255));
Color color = new Color (red, green, blue);
int width = (10 + (int) (40 * Math.random()));
int height = (10 + (int) (40 * Math.random()));
int x = (int) (Math.random() * (getWidth() - width));
int y = (int) (Math.random() * (getHeight() - height));
int velX = 2;
int velY = 2;
int newX = velX + x;
int newY = velY + y;
if (line)
{
shape = new Line2D.Double(x, y, x + width, y + height);
}
else if (rectangle)
{
shape = new Rectangle2D.Double(x, y, width, height);
}
else
{
shape = new Ellipse2D.Double(x, y, width, height);
}
// Here, we want the shapes to stop appearing after reaching a certain size...
if (randomShapes.size() >= 20)
{
break;
}
Shapes randomShape = new Shapes (color, shape);
// Add the shapes to the randomShapes ArrayList...
randomShapes.add (randomShape);
// Here, we are moving the shapes...
for (Shapes shapeMove : randomShapes)
{
if (x < 0 || x > frameWidth - 40)
{
velX = velX * -1;
}
else
{
x = newX;
}
if (y < 0 || y > frameHeight - 40)
{
velY = velY * -1;
}
else
{
y = newY;
}
}
repaint();
}
}
}
ActionListener listener = new TimerListener();
final int DELAY = 100;
Timer t = new Timer(DELAY, listener);
t.start();
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Shapes shape : randomShapes)
{
System.out.println (randomShapes.size());
shape.paint(g2d);
}
g2d.dispose();
}
public static void main (String [] args)
{
// Set up the main frame...
final int FRAME_WIDTH = 800;
final int FRAME_HEIGHT = 500;
JFrame screenSaverFrame = new JFrame ();
screenSaverFrame.setTitle("Homework 6");
screenSaverFrame.setSize (FRAME_WIDTH, FRAME_HEIGHT);
screenSaverFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final MyScreenSaver component = new MyScreenSaver ();
screenSaverFrame.add (component);
screenSaverFrame.setVisible (true);
}
}
Here is the loop specifically...
for (Shapes shapeMove : randomShapes)
{
if (x < 0 || x > frameWidth - 40)
{
velX = velX * -1;
}
else
{
x = newX;
}
if (y < 0 || y > frameHeight - 40)
{
velY = velY * -1;
}
else
{
y = newY;
}
}
I was thinking about placing the contents of the loop inside a void method, but I really don't think that is necessary.
Also, here is my Shape class as well.
import java.awt.*;
public class Shapes
{
private final Color color;
private final Shape shape;
public Shapes (Color color, Shape shape)
{
this.color = color;
this.shape = shape;
}
public Color getColor ()
{
return color;
}
public Shape getShape ()
{
return shape;
}
public void paint(Graphics2D g2d)
{
g2d.setColor(color);
g2d.draw(shape);
g2d.fill(shape);
}
}
The following mre is based on your code. Note the comments documenting the changes made:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
public class MyScreenSaver extends JComponent
{
private final ArrayList <ColoredShape> randomShapes = new ArrayList <>();
//define constants
private static final int FRAME_WIDTH = 800, FRAME_HEIGHT = 500, DELAY = 100, MAX_SHAPE_HEIGHT = 40,
MAX_SHAPE_WIDTH = 40, MIN_SHAPE_HEIGHT = 10, MIN_SHAPE_WIDTH = 40, MAX_SHAPE_COUNT = 20,
LINE_WIDTH = 5, X_STEP = 5, Y_STEP = 5;
//define shape types
enum ShapeType {LINE, RECTANGLE, ELIPSE};
public MyScreenSaver ()
{
ActionListener listener = new TimerListener();
Timer t = new Timer(DELAY, listener);
t.start();
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(LINE_WIDTH));
for (ColoredShape shape : randomShapes) //draw stored shapes
{
shape.paint(g2d);
}
g2d.dispose();
}
//invoked repeatedly by Timer. Each time it adds a shape to the collection
//moves all shapes and repaints
class TimerListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent event)
{
// Create random generation of colors and shapes and location
//up to MAX_SHAPE_COUNT
if (randomShapes.size() < MAX_SHAPE_COUNT)
{
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
Color color = new Color (red, green, blue);
int width = MIN_SHAPE_WIDTH + (int) (MAX_SHAPE_WIDTH * Math.random());
int height = MIN_SHAPE_HEIGHT + (int) (MAX_SHAPE_HEIGHT* Math.random());
int x = (int) (Math.random() * (getWidth() - width));
int y = (int) (Math.random() * (getHeight() - height));
//select a random shape type
int typeIndex = (int) (Math.random()* ShapeType.values().length);
ShapeType type = ShapeType.values()[typeIndex];
// Add the shapes to the randomShapes ArrayList...
randomShapes.add (new ColoredShape (type,color,x, y,width,height));
}
//move the shapes...
for (ColoredShape shape : randomShapes)
{
int x = shape.getX();//get current x position
if (x <= 0 || x > getWidth() - shape.getWidth())
{
shape.setXDirection(-1*shape.getXDirection());//change direction
}
shape.setX(shape.getX() + shape.getXDirection()*X_STEP);//increment
int y = shape.getY();
if (y <= 0 || y > getHeight()- shape.getHeight())
{
shape.setYDirection(-1*shape.getYDirection());
}
shape.setY(shape.getY() + shape.getYDirection()*Y_STEP);
}
repaint();
}
}
public class ColoredShape
{
private int x, y;
private final int width, height;
private int xDirection, yDirection;
private final Color color;
private final ShapeType type;
public ColoredShape(ShapeType type, Color color, int x, int y, int width, int height)
{
this.type = type;
this.color = color;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
xDirection = yDirection = 1; //1 means increase value, -1 decrease value
}
public Color getColor ()
{
return color;
}
private Shape constructShape ()
{
//construct new shape using updated bounds
if(type == ShapeType.LINE)
return new Line2D.Double(x, y, x + width, y + height);
else if (type == ShapeType.RECTANGLE)
return new Rectangle2D.Double(x, y, width, height);
else
return new Ellipse2D.Double(x, y, width, height);
}
public void paint(Graphics2D g2d)
{
g2d.setColor(color);
Shape shape = constructShape();
g2d.draw(shape);
g2d.fill(shape);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getXDirection() {
return xDirection;
}
public void setXDirection(int xDirextion) {
xDirection = xDirextion;
}
public int getYDirection() {
return yDirection;
}
public void setYDirection(int yDirection) {
this.yDirection = yDirection;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
public static void main (String [] args)
{
// Set up the main frame...
JFrame screenSaverFrame = new JFrame ();
screenSaverFrame.setTitle("Homework 6");
screenSaverFrame.setSize (FRAME_WIDTH, FRAME_HEIGHT);
screenSaverFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
screenSaverFrame.add (new MyScreenSaver ());
screenSaverFrame.setVisible (true);
}
}
I am wring the bouncing ball program in java. And I Now have one bouncing ball, I would like to have at least five bouncing balls. I have tried a few ways to do it, however, I only end up with one ball or error.
Do you have any suggestions on how to proceed? This in the piece of code used for the one ball, is it possible to rewrite this piece of code to get multiple balls in a neat way?
import javafx.scene.shape.Rectangle;
public class World {
private final double width, height;
private Ball[] balls;
private final Rectangle pad;
public World(double width, double height) {
this.width = width;
this.height = height;
balls = new Ball[1];
balls[0] = new Ball(10, 10);
balls[0].setVelocity(75.0, 100.0);
pad = new Rectangle(width / 2, 0.9 * height,
width / 8, height / 32);
}
public void move(long elapsedTimeNs) {
balls[0].move(elapsedTimeNs);
constrainBall(balls[0]);
checkForCollisionWithPad(balls[0]);
}
public Ball[] getBalls() {
return (Ball[]) balls.clone();
}
public Rectangle getPad() {
return pad;
}
public void setPadX(double x) {
if (x > width) {
x = width;
}
if (x < 0) {
x = 0;
}
pad.setX(x);
}
private void constrainBall(Ball ball) {
double x = ball.getX(), y = ball.getY();
double dx = ball.getDx(), dy = ball.getDy();
double radius = ball.getRadius();
if (x < radius) {
dx = Math.abs(dx);
} else if (x > width - radius) {
dx = -Math.abs(dx);
}
if (y < radius) {
dy = Math.abs(dy);
} else if (y > height - radius) {
dy = -Math.abs(dy);
}
ball.setVelocity(dx, dy);
}
private void checkForCollisionWithPad(Ball ball) {
if (ball.intersectsArea(
pad.getX(), pad.getY(), pad.getWidth(), pad.getHeight())) {
double dx = ball.getDx();
// set dy negative, i.e. moving "up"
double newDy = -Math.abs(ball.getDy());
ball.setVelocity(dx, newDy);
}
}
}
Main
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Alert;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Bounce extends Application {
private World world;
private Canvas canvas;
private AnimationTimer timer;
protected class BounceTimer extends AnimationTimer {
private long previousNs = 0;
#Override
public void handle(long nowNs) {
if (previousNs == 0) {
previousNs = nowNs;
}
world.move(nowNs - previousNs);
previousNs = nowNs;
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFill(Color.WHITESMOKE);
gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
Rectangle pad = world.getPad();
gc.setFill(Color.BLACK);
double x = pad.getX(), y = pad.getY(),
w = pad.getWidth(), h = pad.getHeight();
gc.fillRoundRect(x, y, w, h, h, h);
for (Ball b : world.getBalls()) {
b.paint(gc);
}
}
}
#Override
public void start(Stage stage) {
Group root = new Group();
Scene scene = new Scene(root, 300, 300, Color.WHITESMOKE);
canvas = new Canvas(scene.getWidth(), scene.getHeight());
root.getChildren().add(canvas);
stage.setTitle("Bounce");
stage.setScene(scene);
stage.setResizable(false);
stage.sizeToScene();
stage.show();
world = new World(canvas.getWidth(), canvas.getHeight());
timer = new BounceTimer();
timer.start();
canvas.addEventHandler(MouseEvent.MOUSE_DRAGGED,
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent me) {
world.setPadX(me.getX());
}
});
}
public static void main(String[] args) {
launch(args);
}
private void showAlert(String message) {
alert.setHeaderText("");
alert.setTitle("Alert!");
alert.setContentText(message);
alert.show();
}
private final Alert alert = new Alert(Alert.AlertType.INFORMATION);
}
Ball
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
public class Ball {
public static final double BILLION = 1_000_000_000.0;
private double x, y; // position of the balls center
private double dx, dy; // velocity measured in pixels/second
private double radius;
private Color color;
public Ball(double x0, double y0) {
x = x0;
y = y0;
radius = 10;
color = Color.MAGENTA;
}
public Ball(double x0, double y0, double rad, Color col) {
x = x0;
y = y0;
radius = rad;
color = col;
}
Ball(int i, int i0, Color BLUEVIOLET) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void setColor(Color col) { // setColor
color = col; }
public double getX() {
return x;
}
public double getY() {
return y;
}
public void setX(double newX) {
x = newX;
}
public void setY(double newY) {
y = newY;
}
public double getRadius() {
return radius;
}
public double getDx() {
return dx;
}
public double getDy() {
return dy;
}
public void setVelocity(double newDx, double newDy) {
dx = newDx;
dy = newDy;
}
public void moveTo(double newX, double newY) {
x = newX;
y = newY;
}
public void move(long elapsedTimeNs) {
x += dx * elapsedTimeNs / BILLION;
y += dy * elapsedTimeNs / BILLION;
}
public void paint(GraphicsContext gc) {
gc.setFill(color);
// arguments to fillOval: see the javadoc for GraphicsContext
gc.fillOval(x - radius, y - radius, radius * 2, radius * 2);
}
public boolean intersectsArea(
double rectX, double rectY,
double rectWidth, double rectHeight) {
double closestX = clamp(x, rectX, rectX + rectWidth);
double closestY = clamp(y, rectY, rectY + rectHeight);
double distanceX = x - closestX;
double distanceY = y - closestY;
return (distanceX * distanceX) + (distanceY * distanceY)
< (radius * radius);
}
private double clamp(double value, double lower, double upper) {
if (value < lower) {
return lower;
}
if (value > upper) {
return upper;
}
return value;
}
}
As Stormblessed said, you are only targeting one ball in your move method.
You should do:
public void move(Ball ball, long elapsedTimeNs) {
ball.move(elapsedTimeNs);
constrainBall(ball);
checkForCollisionWithPad(ball);
}
Edit: Since you want the handler method to accept only the elapsedTimeNs argument, do:
public void move(long elapsedTimeNs) {
for (Ball ball : balls) {
ball.move(elapsedTimeNs);
constrainBall(ball);
checkForCollisionWithPad(ball);
}
}
Edit 2: You should probably have a method that creates a new ball, for convenience:
public Ball newBall(double x, double y, double velocity1, double velocity2) {
Ball tmp = new Ball(x, y);
tmp.setVelocity(velocity1, velocity2);
balls.add(tmp);
return tmp;
}
Edit 3: The reason it throws an error is that you designated balls to have only one index position by using balls = new Ball[1]. You should use an ArrayList (java.util.ArrayList) instead, like so:
import java.util.ArrayList;
ArrayList<Ball> balls = new ArrayList<>;
You should now use balls.add and balls.get instead of = and []. References have been updated accordingly.
To be clear, I want to have a blue circle bouncing left to right which stops on click. This part works. But I also need to have a red rectangle bouncing up and down in the same gui which also stops on click. Each object should stop individually. However, two circles appear where one is moving and the other one is just still. Thanks in Advance! Help is appreciated.
/*
* This program creates an animation for a circle.
*/
package circleanimation;
import java.awt.*;
/*
* #author talhaiqbal18
*/
public class CircleAnimation
{
private int centerX, centerY, radius;
private Color color;
private int direction, speed;
private boolean filled;
public CircleAnimation(int x, int y, int r, Color c) {
centerX = x;
centerY = y;
radius = r;
color = c;
direction = 0;
speed = 0;
filled = false;
}
public void draw(Graphics g) {
Color oldColor = g.getColor();
g.setColor(color);
if (filled) {
g.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.fillRect(200, 200, 200, 200); }
else {
g.fillRect(200, 200, 200, 200);
g.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.setColor(oldColor); }
}
public void fill(Graphics g) {
Color oldColor = g.getColor();
g.setColor(color);
g.fillOval(centerX - radius, centerY - radius, radius * 2, radius * 2);
g.fillRect(200, 200, 200, 200);
g.setColor(oldColor);
}
public boolean containsPoint(int x, int y) {
int xSquared = (x - centerX) * (x - centerX);
int ySquared = (y - centerY) * (y - centerY);
int radiusSquared = radius * radius;
return xSquared + ySquared - radiusSquared <= 0;
}
public void move(int xAmount, int yAmount) {
centerX = centerX + xAmount;
centerY = centerY + yAmount;
}
public int getRadius() {
return radius;
}
public int getX() {
return centerX;
}
public int getY() {
return centerY;
}
public void setSpeed(int s) {
speed = s;
}
public void setDirection(int d) {
direction = d % 360;
}
public void turn(int degrees) {
direction = (direction + degrees) % 360;
}
public void move() {
move((int)(speed * Math.cos(Math.toRadians(direction))),
(int)(speed * Math.sin(Math.toRadians(direction))));
}
public void setFilled(boolean b) {
filled = b;
}
}
/*
* This is the color panel class for the circle animation project.
*/
package circleanimation;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/*
* #author talhaiqbal18
*/
public class ColorPanel extends JPanel
{
private CircleAnimation circle, rectangle;
private javax.swing.Timer timer;
private CircleAnimation selectedCircle, selectedRectangle;
private int x, y;
public ColorPanel(Color backColor, int width, int height) {
setBackground(backColor);
setPreferredSize(new Dimension(width, height));
circle = new CircleAnimation(350, 300, 350, Color.blue);
circle.setDirection(180);
circle.setSpeed(6);
rectangle = new CircleAnimation(350, 300, 400, Color.red);
rectangle.setDirection(90);
rectangle.setSpeed(6);
timer = new javax.swing.Timer(1, new MoveListener());
timer.start();
addMouseListener(new PanelListener());
addMouseMotionListener(new PanelMotionListener());
addMouseMotionListener(new PanelMotionListener1());
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
circle.fill(g);
rectangle.fill(g);
}
private class MoveListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
int x = circle.getX();
int radius = circle.getRadius();
int width = getWidth();
if (x - radius <= 0 || x + radius >= width) {
circle.turn(180);
}
circle.move();
repaint();
}
}
private class MoveListener1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
int x = rectangle.getX();
int radius = rectangle.getRadius();
int width = getWidth();
if (x - radius <= 0 || x + radius >= width) {
rectangle.turn(270);
}
rectangle.move();
repaint();
}
}
private class PanelListener extends MouseAdapter {
public void mousePressed(MouseEvent e)
{
x = e.getX();
y = e.getY();
if (circle.containsPoint(x, y))
selectedCircle = circle;
if (rectangle.containsPoint(x, y))
selectedRectangle = rectangle;
}
public void mouseReleased(MouseEvent e) {
//nothing
}
public void mouseClicked(MouseEvent e) {
if(timer.isRunning())
timer.stop();
else
timer.start();
}
}
private class PanelMotionListener extends MouseMotionAdapter
{
public void mouseDragged(MouseEvent e)
{
int newX = e.getX();
int newY = e.getY();
int dx = newX - x;
int dy = newY - y;
if (selectedCircle != null) {
selectedCircle.move(dx,dy);
x = newX;
y = newY;
repaint(); }
}
}
private class PanelMotionListener1 extends MouseMotionAdapter
{
public void mouseDragged(MouseEvent e)
{
int newX = e.getX();
int newY = e.getY();
int dx = newX - x;
int dy = newY - y;
if (selectedRectangle != null) {
selectedRectangle.move(dx,dy);
x = newX;
y = newY;
repaint(); }
}
}
}
/*
* This is the main method which will implement the actions of the previous classes.
*/
package circleanimation;
import java.awt.*;
import javax.swing.JFrame;
/*
* #author talhaiqbal18
*/
public class MainClass
{
public static void main(String[] args) throws Exception {
JFrame theGUI = new JFrame();
theGUI.setTitle("Circle Animation");
theGUI.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
ColorPanel panel = new ColorPanel(Color.white, 100, 100);
Container pane = theGUI.getContentPane();
pane.add(panel);
theGUI.setVisible(true);
}
}
You only register a timer for your circle, but not for your rectangle in the ColorPanel constructor
i have looked all over the internet and in my school books but I can't seem to slove my problem.
In my program "bouncing ball" (got the code from our teacher) i need to change the size of the ball from small to bigger and reverse. I understand that i need a boolean to do that and maybe alsow an if statment. This is what I have in the Ball class rigth now regarding the size change:
private boolean changeSize = true;
int maxSize = 10;
int minSize = 1;
public void changeSize(boolean size ){
if(size == maxSize ){
return minSize;
}
else return maxSize;
}
public void changeBallSize(int d, int f){
diameter = d*f;
This is the whole code for the class Ball:
class Ball {
static int defaultDiameter = 10;
static Color defaultColor = Color.yellow;
static Rectangle defaultBox = new Rectangle(0,0,100,100);
// Position
private int x, y;
// Speen and angel
private int dx, dy;
// Size
private int diameter;
// Color
private Color color;
// Bouncing area
private Rectangle box;
// New Ball
public Ball( int x0, int y0, int dx0, int dy0 ) {
x = x0;
y = y0;
dx = dx0;
dy = dy0;
color = defaultColor;
diameter = defaultDiameter;
}
// New color
public void setColor( Color c ) {
color = c;
}
public void setBoundingBox( Rectangle r ) {
box = r;
}
// ball
public void paint( Graphics g ) {
// Byt till bollens färg
g.setColor( color );
g.fillOval( x, y, diameter, diameter );
}
void constrain() {
// Ge absoluta koordinater för det rektangulära området
int x0 = box.x;
int y0 = box.y;
int x1 = x0 + box.width - diameter;
int y1 = y0 + box.height - diameter;
// Setting speed and angels
if (x < x0)
dx = Math.abs(dx);
if (x > x1)
dx = -Math.abs(dx);
if (y < y0)
dy = Math.abs(dy);
if (y > y1)
dy = -Math.abs(dy);
}
// movingt the ball
x = x + dx;
y = y + dy;
constrain();
}
}
I am a total rookie of java! Thanks for the help!
Add the following into your Ball class:
private int changeFlag=-1;
In your constrain() function, just before the last line, after moving the ball:
if(diameter==maxSize) {
changeFlag=-1;
}
else if (diameter==minSize) {
changeFlag=1;
}
diameter=diameter+changeFlag;
Add this code to your Ball Class
private minSize = 1;
private maxSize = 10;
public void setDiameter(int newDiameter) {
this.diameter = newDiameter;
}
public int getMinSize() {
return minSize;
}
public int getMinSize() {
return maxSize;
}
Use this when you use the ball
Ball ball = new Ball(1,1,1,1);
int newDiameter = 10;
if(newDiameter == ball.getMinSize()) {
ball.setDiameter(ball.getMaxSize());
}
id(newDiameter == ball.getMaxSize()) {
ball.setDiameter (ball.getMinSize());
}
I've edited it, is this what you mean?
Main Class:
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
public class Main extends JFrame {
public static void main(String[] args) {
new Main();
}
public Main() {
// configure JFrame
setSize(640, 360);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// create ball
Ball ball = new Ball(this.getWidth()/2, this.getHeight()/2, 50, 100);
add(ball);
Thread t = new Thread(ball);
t.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
}
}
Ball Class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JComponent;
public class Ball extends JComponent implements Runnable {
private int x, y, minDiameter, maxDiameter, currentDiameter, growRate = -1;
private Color color = Color.BLUE;
public Ball(int x, int y, int minDiameter, int maxDiameter) {
this.x = x;
this.y = y;
this.minDiameter = minDiameter;
this.maxDiameter = maxDiameter;
this.currentDiameter = minDiameter;
setVisible(true);
}
#Override
public void run() {
while (true) {
// coerce max and min size
if (this.currentDiameter + growRate > maxDiameter) {
this.currentDiameter = maxDiameter;
this.growRate = -1;
}
if (this.currentDiameter + growRate < minDiameter) {
this.currentDiameter = minDiameter;
this.growRate = 1;
}
this.currentDiameter += this.growRate;
repaint();
try {
Thread.sleep(10);
}
catch(Exception e) {
System.out.println(e.toString());
}
}
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
g2.setColor(this.color);
g2.fillOval(this.x, this.y, this.currentDiameter, this.currentDiameter);
}
}
So I'm trying to make a game where I spawn 20 enemies. The enemies are supposed to be loaded into an array of enemies, and then the game is meant to draw them out in a for loop, the only issue is that I keep getting a NullPointerException when I try to run the for loop.
The line in the code below:
enemy[i] = new Enemy(enemyX, enemyY, enemySize, vx, vy);
is the one that's throwing out the exception. I'm listing the full source below as well so you can see what I'm trying to do, I'm just stuck and I need some help on this, is there any other way to create the enemies and place them on the screen?
Main Class:
//define package
package auctus;
//imports
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
//create class
public class Auctus extends BasicGame{
//Window dimensions and title
public static final int WIDTH = 800;
public static final int HEIGHT = 600;
public static final String TITLE = "Auctus 0.1";
//Defining the player variables, obviously only one player to create so no need for
//automation in this area
public float playerX, playerY, playerSize;
//Creating the enemy array
public Enemy enemy[];
//declaring a global variable for the number of enemies
public int numberOfEnemies;
//slick2D API stuff
public Auctus(String title) {
super(TITLE);
}
//initialisation method
public void init(GameContainer gc) throws SlickException {
//setting the number of enemies
numberOfEnemies = 20;
//setting the player variables dynamically each time the game is started
playerX = (float)Math.random() * WIDTH;
playerY = (float)Math.random() * HEIGHT;
playerSize = (float)Math.random() * 50;
//creating the enemies
for(int i = 0; i < numberOfEnemies; i++){
float enemyX = (float)Math.random() * WIDTH;
float enemyY = (float)Math.random() * HEIGHT;
float enemySize = (float)Math.random() * 50;
float vx = (float)Math.random() * 2;
float vy = (float)Math.random() * 2;
//this is the line that's giving me trouble
enemy[i] = new Enemy(enemyX, enemyY, enemySize, vx, vy);
}
}
//from here it doesn't matter, this is error free both syntactically and logically
public void render(GameContainer gc, Graphics g) throws SlickException {
drawPlayer(g, playerX, playerY, playerSize);
for(int i = 0; i < numberOfEnemies; i++){
enemy[i].drawEnemies(g);
}
}
public void update(GameContainer gc, int delta) throws SlickException {
updatePlayer(gc, delta, playerX, playerY, playerSize);
for(int i = 0;i < numberOfEnemies; i++){
enemy[i].updateEnemies(delta);
}
}
public void drawPlayer(Graphics g, float playerX, float playerY, float playerSize){
}
public void updatePlayer(GameContainer gc, int delta, float playerX, float playerY, float playerSize){
}
public void updateEnemies(GameContainer gc, int delta, float enemyX, float enemyY, float enemySize, float vx, float vy){
for(int i = 0; i < numberOfEnemies; i++){
enemyX += vx;
enemyY += vy;
}
}
public static void main(String[] args){
try{
AppGameContainer app = new AppGameContainer(new Auctus(TITLE));
app.start();
} catch(SlickException e){
e.printStackTrace();
}
}
}
Enemy class:
package auctus;
//imports
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
//class declaration
public class Enemy {
//declaring variables
public float enemyX, enemyY, enemySize, vx, vy;
public Enemy(float x, float y, float size, float dx, float dy){
enemyX = x;
enemyY = y;
enemySize = size;
vx = dx;
vy = dy;
}
public float enemyX(){
return enemyY;
}
public float enemyY(){
return enemyY;
}
public float enemySize(){
return enemySize;
}
public float vx(){
return vx;
}
public float vy(){
return vy;
}
public void setX(float x){
enemyX = x;
}
public void setY(float y){
enemyY = y;
}
public void setSize(float size){
enemySize = size;
}
public void setVX(float dx){
vx = dx;
}
public void setVY(float dy){
vy = dy;
}
public void drawEnemies(Graphics g){
g.setColor(Color.red);
g.fillRect(enemyX, enemyY, enemySize, enemySize);
}
public void updateEnemies(int delta){
if(enemyX < 800 || enemyX > 0){
enemyX += vx * delta;
}
if(enemyX > 800 || enemyX < 0){
vx = -vx;
}
if(enemyY < 600 || enemyY > 0){
enemyY += vy * delta;
}
if(enemyY > 600 || enemyY < 0){
vy = - vy;
}
}
}
The enemy class is pretty straight forward. I can't see why it would make that into a NullPointerException, but maybe someone else can spot it.
What am I doing wrong?
You never instantiate your array enemy.
At some point, before you use enemy, you'll need something like: enemy = new Enemy[numEnemies];. You can do it in the declaration:
// use a constant for the number of enemies:
public static final int NUM_ENEMIES = 20;
Enemy enemy[] = new Enemy[NUM_ENEMIES];
Otherwise, since enemy is null - because you haven't instantiated it - you'll get a NullPointerException when you try to index it.