I need some help figuring out how to capture and store collisions in a frogger game. I've managed to get the game to run fairly smoothly and now want to add collisions to the game. After some research I've found that rectangles seem like a viable option for my game, however, I'm not sure where I should start to actually capture a collision from an "enemy" and a "player". Here is my code so far:
public class myJPanel0 extends JPanel implements KeyListener, ActionListener
//This panel will contain the game
{
JButton menu;
Image myImage;
Graphics g;
myJPanel1 p1;
// Border[] gameBorder = new Border[]{BorderFactory.createTitledBorder("Border types")};
gameOverJPanel gp;
JButton lion = new JButton(new ImageIcon("images/download.jpg"));
JButton yard = new JButton("50 Yardline");
JButton score = new JButton("Touchdown");
JButton start = new JButton("Start");
JButton scoreKeeper = new JButton("Your score is");
JButton lives = new JButton("Lives left = ");
Timer tim;
int delay = 100;
int x = 296;
int y = 685;
int counter = 0;
ButtonObject[] enemies = new ButtonObject[10];
ButtonObject[] enemies1 = new ButtonObject[10];
ImageIcon icon[] = new ImageIcon[10];
public myJPanel0(myJPanel1 informedp1, gameOverJPanel informedgp)
{
super();
setLayout(null);
p1 = informedp1;
gp = informedgp;
setBackground(Color.MAGENTA);
menu = new JButton("Menu");
scoreKeeper.setBounds(16,80,200,55);
lives.setBounds(417, 80,200,55);
lion.setBounds(x,y,40,55);
score.setBounds(16,135,601,55);
yard.setBounds(16,410,601,55);
start.setBounds(16,685,601,55);
menu.setBounds(new Rectangle(250,5,80,30));
add(menu);
add(lives);
add(lion);
add(yard);
add(start);
add(scoreKeeper);
add(score);
setFocusable(true);
addKeyListener(this);
tim = new Timer(delay, this);
tim.start();
for (int i = 0; i <= 3; i++){ // loop that cycles through first half of enemy creation
String text = String.valueOf(i);
int y = 630 - (i * 55);
int x = 16;
enemies[i] = new ButtonObject(text+"??", x, y, 40, 55);
enemies[i].setBounds(new Rectangle(x, y, 40,55));
add(enemies[i]);
}
for (int i = 0; i <= 3; i++){ // second have enemy creation
String text = String.valueOf(i);
int y = 355 - (i * 55);
int x = 16;
enemies1[i] = new ButtonObject(text+"??", x, y, 40, 55);
enemies1[i].setBounds(new Rectangle(x, y, 40,55));
add(enemies1[i]);
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Image myLion = Toolkit.getDefaultToolkit().getImage("images/download.jpg");
g.drawImage(myLion,296,355,40,55,this);
if(p1.myImage1 == 1)
{
super.paintComponent(g);
Image myImage = Toolkit.getDefaultToolkit().getImage("images/snow.jpg");//Place holder for now, we can come up with our own image.
g.drawImage(myImage, 0, 0,680,880, this);
requestFocusInWindow();
}else if(p1.myImage1 == 2)
{
super.paintComponent(g);
Image myImage = Toolkit.getDefaultToolkit().getImage("images/grass.jpg");//Place holder for now, we can come up with our own image.
g.drawImage(myImage, 0, 0,680,880, this);
requestFocusInWindow();
}
else{
super.paintComponent(g);
Image myImage = Toolkit.getDefaultToolkit().getImage("images/stone.jpg");//Place holder for now, we can come up with our own image.
g.drawImage(myImage, 0, 0,680,880, this);
requestFocusInWindow();
}
}
public void keyPressed(KeyEvent evt)
{
System.out.println("Key pressed");
int kk = evt.getKeyCode();
if(kk == evt.VK_LEFT) {x=x-40;}
else if(kk == evt.VK_RIGHT) {x=x+40;}
else if(kk == evt.VK_UP) {y=y-55;}
else if(kk == evt.VK_DOWN) {y=y+55;}
lion.setBounds(x,y,40,55);
System.out.println(x);
System.out.println(y);
if(y <= 135){
counter = counter + 1;
scoreKeeper.setText("Your score is " + counter);
y = 740;
}
}
public void keyReleased(KeyEvent evt) { }
public void keyTyped(KeyEvent evt) { }
public void actionPerformed(ActionEvent event) {
for (int i = 0; i <= 3; i++)
{
enemies[i].move();
}
for (int i = 0; i <= 3; i++)
{
enemies1[i].move();
}
}
}
Related
As a project, I'm attempting to create an emulation of the game Asteroids. Currently, I'm trying to make it so then the spaceship appears on the opposite side of the GUI if the player ever sends himself out of bounds.
However, I've become quite confused between how AffineTransformation's rotate and createTransformedShape function interacts with the x and y points of the polygon.
Currently, I have the spaceship working; it flies in the angle the user specifies it and all the movement involved works fine. However, when I tried to get the lowest X coordinate of the spaceship to compare if it ever goes bigger than the constant WIDTH, it returns 780. This happens all the time whether or not I am on one side of the map to the other, it always returns 780. This I find really strange because shouldn't it return the smallest X coordinate of where it currently is?
Here is a screenshot of the console displaying that the "smallest x coordinate" of the polygon is 780, despite not being at 780
Can someone explain to me why the X coordinates of the polygon are not changing? I have 2 classes. One, which is the driver classes, and the other which is the ship class which extends Polygon.
public class AsteroidGame implements ActionListener, KeyListener{
public static AsteroidGame game;
public Renderer renderer;
public boolean keyDown = false;
public int playerAngle = 0;
public boolean left = false;
public boolean right = false;
public boolean go = false;
public boolean back = false;
public boolean still = true;
public double angle = 0;
public int turnRight = 5;
public int turnLeft = -5;
public Shape transformed;
public Shape transformedLine;
public Point p1;
public Point p2;
public Point center;
public Point p4;
public final int WIDTH = 1600;
public final int HEIGHT = 800;
public Ship ship;
public AffineTransform transform = new AffineTransform();
public AsteroidGame(){
JFrame jframe = new JFrame();
Timer timer = new Timer(20, this);
renderer = new Renderer();
jframe.add(renderer);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setSize(WIDTH, HEIGHT);
jframe.setVisible(true);
jframe.addKeyListener(this);
jframe.setResizable(false);
int xPoints[] = {800, 780, 800, 820};
int yPoints[] = {400, 460, 440, 460};
p1 = new Point(400,400);
p2 = new Point(380, 460);
center = new Point(400,440);//center
p4 = new Point(420, 460);
ship = new Ship(xPoints, yPoints, 4, 0);
transformed = transform.createTransformedShape(ship);
timer.start();
}
public void repaint(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(0, 0, WIDTH, HEIGHT);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.WHITE);
g2d.draw(transformed);
/*
g2d.draw(r2);
Path2D.Double path = new Path2D.Double();
path.append(r, false);
AffineTransform t = new AffineTransform();
t.rotate(Math.toRadians(45));
path.transform(t);
g2d.draw(path);
Rectangle test = new Rectangle(WIDTH/2, HEIGHT/2, 200, 100);
Rectangle test2 = new Rectangle(WIDTH/2, HEIGHT/2, 200, 100);
g2d.draw(test2);
AffineTransform at = AffineTransform.getTranslateInstance(100, 100);
g2d.rotate(Math.toRadians(45));
g2d.draw(test);
*/
}
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
if (right){
ship.right();
transform.rotate(Math.toRadians(turnRight), ship.getCenterX(), ship.getCenterY());
System.out.println(ship.getCenterY());
}
else if (left){
ship.left();
transform.rotate(Math.toRadians(turnLeft), ship.getCenterX(), ship.getCenterY());
}
if (go){
ship.go();
//ship.x += Math.sin(Math.toRadians(angle)) * 5;
//ship.y
/*
ship.x += (int) Math.sin(Math.toRadians(angle));
ship.y += (int) Math.cos(Math.toRadians(angle));
*/
//System.out.println(Math.sin(Math.toRadians(ship.angle)) * 5 + "y" + Math.cos(Math.toRadians(ship.angle)) * 5);
}
else if (back){
ship.reverse();
}
ship.move();
//ship.decrement();
transformed = transform.createTransformedShape(ship);
if (ship.smallestX() >= WIDTH){
System.out.println("out");
}
renderer.repaint();
System.out.println("Smallest x coordinate: " + ship.smallestX());
}
public static void main(String[] args){
game = new AsteroidGame();
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == KeyEvent.VK_RIGHT){
System.out.println("I am down");
right = true;
keyDown = true;
}else if (e.getKeyCode() == KeyEvent.VK_LEFT){
left = true;
System.out.println("I am down");
keyDown = true;
}
if (e.getKeyCode() == KeyEvent.VK_UP){
go = true;
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN){
back = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == KeyEvent.VK_RIGHT){
right = false;
}
if (e.getKeyCode() == KeyEvent.VK_LEFT){
left = false;
}
if (e.getKeyCode() == KeyEvent.VK_UP){
go = false;
}
if (e.getKeyCode() == KeyEvent.VK_DOWN){
back = false;
}
still = true;
keyDown = false;
System.out.println("up");
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
Ship Class:
public class Ship extends Polygon{
/**
*
*/
private double currSpeed = 0;
private static final long serialVersionUID = 1L;
public double angle;
public Ship(int[] x, int[] y, int points, double angle){
super(x, y, points);
this.angle= angle;
}
public void right(){
angle += 5;
}
public void left(){
angle -= 5;
}
public void move(){
for (int i = 0; i < super.ypoints.length; i++){
super.ypoints[i] -= currSpeed;
//System.out.println(super.ypoints[i]);
//System.out.println(super.xpoints[i]);
}
}
public void reverse(){
if (currSpeed > -15) currSpeed -= 0.2;
}
public void go(){
if (currSpeed < 25) currSpeed += 0.5;
}
public int smallestX(){
int min = super.xpoints[0];
for (int i = 0; i < super.xpoints.length; i++){
if (min > super.xpoints[i]){
min = super.xpoints[i];
}
}
return min;
}
public int smallestY(){
int min = super.ypoints[0];
for (int i = 0; i < super.ypoints.length; i++){
if (min < super.ypoints[i]){
min = super.ypoints[i];
}
}
return min;
}
public int getCenterX(){
return super.xpoints[2];
}
public int getCenterY(){
return super.ypoints[2];
}
public double getAng(){
return angle;
}
Why it doesn't work
The affine transformation doesn't actually affect the ship instance, instead it created an entirely new instance, this is why your method doesn't seem to work. To prove this, i have the following code:
int[] xPoints = {800, 780, 800, 820};
int[] yPoints = {400, 460, 440, 460};
Ship ship = new Ship(xPoints, yPoints, 4, 0);
System.out.println("old points:");
System.out.println(Arrays.toString(ship.xpoints));
System.out.println(Arrays.toString(ship.ypoints));
AffineTransform transform = new AffineTransform();
transform.translate(20, 20);
Shape transformed = transform.createTransformedShape(ship);
System.out.println("new points (unchanged):");
System.out.println(Arrays.toString(ship.xpoints));
System.out.println(Arrays.toString(ship.ypoints));
Both times, the points are the same.
Solution
What i suggest you do is instead of thinking of the point as actual points on the screen, think of them as a model, that will also make the physics part easier. We'll center the points around (0,0). And when we need to render it, tranform it to the correct position and rotation.
The points would then be something like this:
int[] xPoints = {0, -20, 0, 20};
int[] yPoints = {-40, 20, 0, 20};
So now, you don't need to edit all the points when you move the ship, only the rotation and the center. Note that you should translate first, and then rotate.
The fact that these point are around (0,0) is important, because this is the center of your rotation. This is probably why you seem to be able to move at the moment, your rotation is not centered around the center of the ship. And when you rotate and move up, you also move a bit to the right.
This solves our problem, because now you don't need to look at all the points anymore, you can just check the center of the ship. If the center goes out of bounds, move it to the other side.
Resulting in the folliwing simple code (i use 300 here because that's the width and height in my example, change it to your width and height in the actual code)
if(center_x > 300)
center_x = 0;
if(center_x < 0)
center_x = 300;
if(center_y > 300)
center_y = 0;
if(center_y < 0)
center_y = 300;
This will take the ship to the other side of the screen when needed. However, we still need to show part of the ship while the other part is on the other side. For that reason, we can just render the ship twice. I hope the following code speaks for itself.
Rectangle2D box = transformed.getBounds2D();
//wrap in x direction
if(box.getX() + box.getWidth() > 300){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x - 300, ship.center_y);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}else if(box.getX() < 0){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x + 300, ship.center_y);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}
//wrap in y direction
if(box.getY() + box.getHeight() > 300){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x, ship.center_y - 300);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}else if(box.getY() < 0){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x, ship.center_y + 300);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}
Physics
You also requested more info on the actual physics, i'll just give you the formulas (let me know if you need more help). Here, theta is the angle of the ship in radians, where if theta is 0, the ship points up. The x-axis points to the right, and the y-axis points up.
a_x = Math.sin(theta)*a;
a_y = -Math.cos(theta)*a;
v_x_new = v_x_old + a_x*timeDiff;
v_y_new = v_y_old + a_y*timeDiff;
x_new = x_old + v_x_old*timeDiff + a_x*timeDiff*timeDiff/2;
y_new = y_old + v_y_old*timeDiff + a_y*timeDiff*timeDiff/2;
x_old = x_new;
y_old = y_new;
v_x_old = v_x_new;
v_y_old = v_y_new;
Final result
I've implemented how the ship class should look, and also tested if the rendering method works.
public class AsteroidsTest {
public static void main(String[] args){
int[] xPoints = {0, -20, 0, 20};
int[] yPoints = {-40, 20, 0, 20};
Ship ship = new Ship(xPoints, yPoints, 4, 0);
ship.center_x = 100;
ship.center_y = 100;
ship.angle = 45;
ship.speed_x = 30;
ship.speed_y = -30;
System.out.println("running...");
JFrame window = new JFrame();
window.setBounds(30, 30, 300, 300);
window.getContentPane().add(new MyCanvas(ship));
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
long time1 = System.currentTimeMillis();
while(true){
long time2 = System.currentTimeMillis();
double timeDiff = (time2-time1)/1000f;
time1 = time2;
ship.move(timeDiff);
window.getContentPane().repaint();
}
}
}
class MyCanvas extends JComponent {
private Ship ship;
public MyCanvas(Ship ship){
this.ship = ship;
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
AffineTransform transform = new AffineTransform();
transform.translate(ship.center_x, ship.center_y);
transform.rotate(Math.toRadians(ship.angle));
Shape transformed = transform.createTransformedShape(ship);
g2.draw(transformed);
Rectangle2D box = transformed.getBounds2D();
//wrap in x direction
if(box.getX() + box.getWidth() > 300){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x - 300, ship.center_y);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}else if(box.getX() < 0){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x + 300, ship.center_y);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}
//wrap in y direction
if(box.getY() + box.getHeight() > 300){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x, ship.center_y - 300);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}else if(box.getY() < 0){
AffineTransform transform2 = new AffineTransform();
transform2.translate(ship.center_x, ship.center_y + 300);
transform2.rotate(Math.toRadians(ship.angle));
Shape transformed2 = transform2.createTransformedShape(ship);
g2.draw(transformed2);
}
}
}
Ship class:
import java.awt.Polygon;
public class Ship extends Polygon{
private static final long serialVersionUID = 1L;
public double center_x = 0;
public double center_y = 0;
public double speed_x = 0;
public double speed_y = 0;
//the angle of the ship
public double angle = 0;
//the acceleration of the ship in the direction defined by angle
public double acceleration = 0;
public Ship(int[] x, int[] y, int points, double angle){
super(x, y, points);
this.angle= angle;
}
public void right(){
angle += 5;
}
public void left(){
angle -= 5;
}
public void move(double timeDiff){
double a_x = Math.sin(Math.toRadians(angle))*acceleration;
double a_y = -Math.cos(Math.toRadians(angle))*acceleration;
center_x = center_x + speed_x*timeDiff + a_x*timeDiff*timeDiff/2;
center_y = center_y + speed_y*timeDiff + a_y*timeDiff*timeDiff/2;
speed_x = speed_x + a_x*timeDiff;
speed_y = speed_y + a_y*timeDiff;
if(center_x > 300)
center_x = 0;
if(center_x < 0)
center_x = 300;
if(center_y > 300)
center_y = 0;
if(center_y < 0)
center_y = 300;
}
public void reverse(){
acceleration = -1;
}
public void go(){
acceleration = 1;
}
public void stop(){
acceleration = 0;
}
public int getCenterX(){
return (int) Math.round(center_x);
}
public int getCenterY(){
return (int) Math.round(center_y);
}
public double getAng(){
return angle;
}
}
Currently I'm studying Computer Science and my teacher want me to make a snake game with array.
I have this code that is exactly same as my friend's but it only grow one body length and won't grow longer and after it eats the food it starts to slow down the speed of moving snake. I'm not sure where I went wrong please help. Thank you.
Here's the code:
public class Main extends JPanel implements KeyListener, ActionListener {
private static final long serialVersionUID = 1L;
static int dir;
static int i;
static int x[] = new int[200]; // Decleare Array of snake on x coordinate
static int y[] = new int[200]; // Decleare Array of snake on y coordinate
static int taillength = 1;
static int sxinc = 20, syinc = 20; // Speed of moving snake
static int fx = 100, fy = 100; // Declare the position of where food at
static int f2x = 300, f2y = 300; // Declare the position of where food2 at
static int fmx = 300, fmy = 100; // Declare the position of where food3 at
static int score = 0; // Create Score Counter
static int width = 745, height = 489; // Declare the size of JPanel
static int nsx, nsy; // The new value of the snake movement
static int csx = 20, csy = 20; // The value to add/minus on the number to
static BufferedImage background = null;
static JFrame f;
static JFrame g;
public Main() {
addKeyListener(this);
}
public void addNotify() {
super.addNotify();
requestFocus();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background, 0, 0, width, height, this);
g.setColor(Color.GREEN);
g.fillRect(fx, fy, 20, 20);
g.setFont(new Font("Times New Roman", Font.BOLD, 15));
g.setColor(Color.GREEN);
g.drawString("GREEN - Add 1 body length, add 1 score", 0, 429);
g.setColor(Color.BLUE);
g.fillRect(f2x, f2y, 20, 20);
g.setFont(new Font("Times New Roman", Font.BOLD, 15));
g.setColor(Color.BLUE);
g.drawString("BLUE - Add 2 body length, add 2 score", 0, 444);
g.setColor(Color.CYAN);
g.fillRect(fmx, fmy, 20, 20);
g.setFont(new Font("Times New Roman", Font.BOLD, 15));
g.setColor(Color.CYAN);
g.drawString("CYAN - Minus 1 body length, add 1 score", 0, 459);
g.setColor(Color.RED);
for (int j = 0; j < x.length && j < taillength; j++) {
g.fillRect(x[j], y[j], 20, 20);
g.setColor(Color.ORANGE);
}
g.fillRect(x[0], y[0], 20, 20);
g.setColor(Color.RED);
g.setFont(new Font("Times New Roman", Font.BOLD, 25));
g.setColor(Color.WHITE);
g.drawString("Score : " + score, 305, 459);
}
public void snakenew() {
for (int i = 0; i < x.length; i++) {
x[i] = 0;
y[i] = 0;
}
}
public static void main(String a[]) {
x[0] = 300;
y[0] = 220;
try { // Import Background
background = ImageIO.read(new File("H:/shutterstock_12730534.jpg"));
} catch (IOException e) {
}
Main p = new Main();
g = new JFrame();
g.add(p);
g.setSize(200, 300);
g.setVisible(true);
g.setResizable(false);
f = new JFrame();
f.add(p);
f.setSize(width, height);
f.setVisible(true);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Timer t = new Timer(60, p);
t.start();
}
public void actionPerformed(ActionEvent e) {
if ((x[0] + 20 > width) || (x[0] < 0) || (y[0] + 40 > height)
|| (y[0] < 0)) { // Game over when hit the wall
JOptionPane.showMessageDialog(null, "You hit the wall!", "Game",
JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
}
if ((taillength > 1) && (x[i] != x[0]) && (y[i] != y[0])) { // Game over
// when
// touch you
// snake
// body
if ((x[0] == x[i]) & (y[0] == y[i])) {
JOptionPane.showMessageDialog(null, "You ran into yourself!",
"Game", JOptionPane.INFORMATION_MESSAGE);
}
}
if (dir == KeyEvent.VK_UP) {
if (y[0] == y[taillength]) {
y[0] = y[0] - syinc;
}
}
else if (dir == KeyEvent.VK_DOWN) {
if (y[0] == y[taillength]) {
y[0] = y[0] + syinc;
}
}
else if (dir == KeyEvent.VK_LEFT) {
if (x[0] == x[taillength]) {
x[0] = x[0] - sxinc;
}
}
else if (dir == KeyEvent.VK_RIGHT) {
if (x[0] == x[taillength]) {
x[0] = x[0] + sxinc;
}
}
if (dir == KeyEvent.VK_K) {
if ((score > 6) && (taillength > 5)) {
taillength = taillength - 5;
score = score - 7;
}
}
if ((x[0] == fx) && (y[0] == fy)) { // Food Score and random food
fx = (int) (Math.random() * 37) * 20;
fy = (int) (Math.random() * 25) * 20;
taillength++;
score++;
}
if ((x[0] == f2x) && (y[0] == f2y)) {
f2x = (int) (Math.random() * 37) * 20;
f2y = (int) (Math.random() * 25) * 20;
taillength = taillength + 2;
score = score + 2;
}
if ((x[0] == fmx) && (y[0] == fmy)) {
if (taillength > 0) {
fmx = (int) (Math.random() * 37) * 20;
fy = (int) (Math.random() * 25) * 20;
taillength--;
score++;
}
}
for (i = taillength; i > 0; i--) {
x[i] = x[(i - 1)];
y[i] = y[(i - 1)];
}
f.repaint();
}
public void keyPressed(KeyEvent ke) {
dir = ke.getKeyCode();
}
public void keyReleased(KeyEvent arg0) {
}
public void keyTyped(KeyEvent arg0) {
}
}
A few things:
You are using a timer, but the item you are putting in the timer has no run() method... That's not how a timer works (please reference the last point as to why).
You are redrawing the whole screen every single time you tick. Not only is that ridiculous, it is most likely the cause of your aforementioned lag when you grow the body. Fixing this will ensure that you experience little to now lag between growth (although, you will still need to compensate at later growths by changing the speed of the snake; this, will also make the game more difficult as you go on, just like real Snake). This usage of the paint() method, can be attributed to the same reasoning as the last point.
You took someone elses code. Don't use code that doesn't belong to you--it might work, and you're fine, or you might have the same bug as the other guy, and now you've got a great time explaining why you have the copied code of some other student.
In conclusion: if you want to borrow code, never borrow code from someone who is in the same course as you. Finally, look up some examples of Snake games in Java. I'm sure you'll find some people who have experienced similar problems, from whom you might learn. I hope this helps you, and best of luck!
I am writing the implementation of Galton Board in Java by using Java awt, Swing and thread. My Program has three text field to choose number of slots, number of balls, and number of ball drops at the same time, two buttons one for display and one for start the program. I try to make it work like I can choose the amount of balls and click start and the balls auto falling down the chimney. Currently, My program be able to drop one ball and running fine, but I don't know how to implement that be able drop more than one ball. Any suggestions or help are appreciated, Thank you. This is Main.Class
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.Random;
import javax.swing.*;
public class Main extends JFrame {
private String num_slots;
private String num_balls;
private String ball_free;
private JButton Display;
private JButton Start;
private JPanel textpanel;
private JPanel mainpanel;
private JPanel graphpanel;
public Main() {
textpanel = new JPanel();
textpanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 20));
textpanel.add(new JLabel("Number of Slots"));
final JTextField text1 = new JTextField(10);
textpanel.add(text1);
textpanel.add(new JLabel("Number of Balls"));
final JTextField text2 = new JTextField(10);
textpanel.add(text2);
textpanel.add(new JLabel("How many balls can be freed"));
final JTextField text3 = new JTextField(10);
textpanel.add(text3);
Display = new JButton("Display");
textpanel.add(Display);
Start = new JButton("Start");
textpanel.add(Start);
// Create panel p2 to hold a text field and p1
mainpanel = new JPanel(new BorderLayout());
mainpanel.add(textpanel, BorderLayout.NORTH);
/*
* graphpanel = new JPanel(); graphpanel.setLayout(new
* BoxLayout(graphpanel, BoxLayout.Y_AXIS));
*/
add(mainpanel, BorderLayout.CENTER);
Display.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Display) {
num_slots = text1.getText();
int slots = Integer.parseInt(num_slots);
num_balls = text2.getText();
int balls = Integer.parseInt(num_balls);
MainPanel pa = new MainPanel(slots, balls);
mainpanel.add(pa);
mainpanel.revalidate();
}
}
});
Start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Start) {
num_slots = text1.getText();
int slots = Integer.parseInt(num_slots);
num_balls = text2.getText();
int balls = Integer.parseInt(num_balls);
MainPanel pa = new MainPanel(slots, balls);
mainpanel.add(pa, BorderLayout.CENTER);
pa.start();
mainpanel.revalidate();
mainpanel.repaint();
}
}
});
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Main frame = new Main();
frame.setTitle("The Galton board");
frame.setSize(1000, 800);
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setAutoRequestFocus(true);
}
}
main panel class contains the chimneys and balls
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JPanel;
class MainPanel extends JPanel implements Runnable {
private int num;
private int number_ball;
public static int start_y = 100;
private float ball_x = 385;
private float ball_y = 50;
private float radius = 15;
private static int panel_x = 300;
private static int panel_y = 100;
private int diameter = 20;
private int last_x = 0;
private final static Random generator = new Random();
ArrayList<Balls> list_ball = new ArrayList<Balls>();
private int m_interval = 100;
private Timer m_timer;
public MainPanel() {
}
public MainPanel(int number) {
num = number;
}
public MainPanel(int number, int ball) {
num = number;
number_ball = ball;
for (int i = 1; i <= number_ball; i++)
{
list_ball.add(new Balls());
}
m_timer = new Timer(m_interval, new TimerAction());
}
public int getPanel_y() {
return panel_y;
}
public void start()
{
m_timer.setInitialDelay(250);
m_timer.start();
}
#Override
protected void paintComponent(Graphics g) {
int start_y = 100;
panel_x = 300;
panel_y = 100;
diameter = 20;
last_x = 0;
super.paintComponent(g);
if (num % 2 == 0) {
for (int i = 1; i <= num; i++) {
if ((i % 2) != 0) {
for (int k = 1; k <= num; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
} else if ((i % 2) == 0) {
for (int k = 1; k <= num + 1; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x - 20, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
}
panel_y = panel_y + 40;
panel_x = 300;
}
} else if (num % 2 != 0) {
for (int i = 1; i <= num; i++) {
if ((i % 2) != 0) {
for (int k = 1; k <= num; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
} else if ((i % 2) == 0) {
for (int k = 1; k <= num + 1; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x - 20, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
}
panel_y = panel_y + 40;
panel_x = 300;
}
}
for (int n = 40; n < panel_y - 40; n = n + 40) {
if (num % 2 == 0) {
g.drawLine(panel_x - 50 + n, panel_y - 10, panel_x - 50 + n,
panel_y + 80);
g.drawLine(panel_x, panel_y + 80, panel_x - 50 + n, panel_y + 80);
last_x = panel_x - 50 + n;
} else if (num % 2 != 0) {
g.drawLine(panel_x - 30 + n, panel_y - 10, panel_x - 30 + n,
panel_y + 80);
g.drawLine(panel_x, panel_y + 80, panel_x - 30 + n, panel_y + 80);
last_x = panel_x - 30 + n;
}
}
for (int i = 0; i< list_ball.size(); i++)
{
list_ball.get(i).draw(g);
}
}
class TimerAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i< list_ball.size(); i++)
{
list_ball.get(i).move();
//return;
//m_timer.stop();
repaint();
}
}
Balls Class
import java.awt.geom.Ellipse2D;
import java.util.Random;
import java.awt.*;
public class Balls {
private Ellipse2D.Double thisBall;
private int Ball_x;
private int Ball_y;
public int radius;
public int start_y;
private final static Random generator = new Random();
Mainpanel pa = new Mainpanel();
public Balls()
{
start_y = 100;
Ball_x = 385;
Ball_y = 50;
radius = 15;
}
public void draw(Graphics g)
{
g.setColor(Color.RED);
g.fillOval(Ball_x, Ball_y, radius, radius);
}
public void move()
{
if (Ball_y < pa.getPanel_y() + 65)
{
int direction = generator.nextInt(2);
Ball_y = Ball_y + 5;
if (Ball_y == start_y - 10 && start_y < pa.getPanel_y())
{
if (direction == 0)
{
Ball_x = Ball_x - 20;
}
else Ball_x = Ball_x + 20;
start_y = start_y + 40;
}
System.out.println(Ball_y);
System.out.println(pa.getPanel_y());
}
// Ball_x = Ball_x + 5;
}
}
Create a new logical class, not a GUI class, for your Ball, one that does not extend a JPanel or any Swing component, but rather one that has the logic behind the Ball as well as perhaps a rendering method that accepts a Graphics or Graphics2D object. Then give your drawing JPanel class an ArrayList of these Ball objects, move them in your game loop -- note that I would prefer using a Swing Timer and not a background thread, and then in your JPanel's paintComponent method iterate through the ArrayList of Balls, drawing each Ball by calling its rendering method.
As an aside: all your class names should begin with an upper case letter, and all identifiers other than constants should use camel case, so your mainpanel class should be named MainPanel. I've edited your code prettify the code formatting and have made this change for you.
Aside number 2: your current code has code logic inside of paintComponent. Don't do that as that will mess you up. You don't have full control over when or even if paintComponent will be called.
I have a set of sprites that I am calling in a Java game, and when I had 3 sprites it worked fine, but when I add a fourth sprite, the repaint method is only called every other time.
Here is my minimal example,
Main class:
public class Maze extends JPanel implements ActionListener{
/**
* #param args
*/
int stage;
int dir;
int x = 32;
int y = 32;
Rectangle r = new Rectangle(x,y,10,10);
Draw D = new Draw();
public static ArrayList<Rectangle> walls = new ArrayList<Rectangle>();
public ArrayList<Image> spritesl = new ArrayList<Image>();
public ArrayList<Image> spritesd = new ArrayList<Image>();
public ArrayList<Image> spritesr = new ArrayList<Image>();
public ArrayList<Image> spritesu = new ArrayList<Image>();
BufferedImage image;
public Maze() throws IOException{
setBackground(Color.black);
setSize(672,672);
Timer timer = new Timer(2000,this);
timer.addActionListener(this);
timer.start();
//add sprites
for(int i = 1; i<5; i += 1){
spritesl.add(image = ImageIO.read(new File("C:/Users/Dave/Desktop/Sprites/left" + i + ".png")));
}
for(int i = 1; i<5; i += 1){
spritesd.add(image = ImageIO.read(new File("C:/Users/Dave/Desktop/Sprites/down" + i + ".png")));
}
for(int i = 1; i<5; i += 1){
spritesr.add(image = ImageIO.read(new File("C:/Users/Dave/Desktop/Sprites/right" + i + ".png")));
}
for(int i = 1; i<5; i += 1){
spritesu.add(image = ImageIO.read(new File("C:/Users/Dave/Desktop/Sprites/up" + i + ".png")));
}
}
public static void main(String[] args) throws IOException {
JFrame frame = new JFrame();
Maze ate = new Maze();
frame.addKeyListener(new Input());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(ate);
frame.setPreferredSize(new Dimension(688, 709));//16, 37
frame.setVisible(true);
frame.pack();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
//call wall drawer
g.setColor(Color.gray);
D.draw(g);
g.setColor(Color.red);
//set animation
if(dir == 1){
g.drawImage(spritesu.get(stage-1),x,y, this);
}else if(dir == 2){
g.drawImage(spritesr.get(stage-1),x,y, this);
}else if(dir == 3){
g.drawImage(spritesd.get(stage-1),x,y, this);
}else if(dir == 4){
g.drawImage(spritesl.get(stage-1),x,y, this);
}
System.out.println("set");
}
#Override
public void actionPerformed(ActionEvent e) {
boolean up =false;
boolean right =false;
boolean down =false;
boolean left =false;
//next part tests each direction for collisions
if(Input.right){
right = true;
x += 4;
if(x>672-32){
x -= 4;
right = false;
}else{
for(int i = 0; i < walls.size(); i += 1){
if(new Rectangle(x, y, 30, 30).intersects(walls.get(i))){
x -= 4;
right = false;
}
}
}
}
if(Input.left){
left = true;
dir=4;
x-=4;
if(x<0){
x += 4;
left = false;
}else{
for(int i = 0; i < walls.size(); i += 1){
if(new Rectangle(x, y, 32, 32).intersects(walls.get(i))){
x += 4;
left = false;
}
}
}
}
if(Input.down){
down = true;
dir=3;
y+=4;
if(y>672-32){
y -= 4;
down = false;
}else{
for(int i = 0; i < walls.size(); i += 1){
if(new Rectangle(x, y, 32, 32).intersects(walls.get(i))){
y -= 4;
down = false;
}
}
}
}
if(Input.up){
up = true;
dir=1;
y-=4;
if(y<0){
y += 4;
up = false;
}else{
for(int i = 0; i < walls.size(); i += 1){
if(new Rectangle(x, y, 32, 32).intersects(walls.get(i))){
y += 4;
up = false;
}
}
}
}
//sets direction of animation
if(left||down||right||up){
if(left){
dir = 4;
}
if(down){
dir = 3;
}
if(right){
dir = 2;
}
if(up){
dir = 1;
}
stage += 1;
if(stage >= 4 || stage <= 0){
stage = 1;
}
System.out.println(stage);
}
repaint();
}
}
My input tester(probably not necessary, but its needed for the game to run):
public class Input implements KeyListener {
public static boolean left = false;
public static boolean right = false;
public static boolean up = false;
public static boolean down = false;
public static boolean space = false;
//test for keys
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
left = true;
if (key == KeyEvent.VK_RIGHT)
right = true;
if (key == KeyEvent.VK_UP)
up = true;
if (key == KeyEvent.VK_DOWN)
down = true;
if (key == KeyEvent.VK_SPACE)
space = true;
}
#Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
left = false;
if (key == KeyEvent.VK_RIGHT)
right = false;
if (key == KeyEvent.VK_UP)
up = false;
if (key == KeyEvent.VK_DOWN)
down = false;
if (key == KeyEvent.VK_SPACE)
space = false;
}
#Override
public void keyTyped(KeyEvent e) {}
}
and my Draw class:
public class Draw {
public void draw(Graphics g){
//draw everything
Maze.walls.clear();
g.fillRect(0, 0, 672, 32);
g.fillRect(0, 0, 32, 672);
g.fillRect(0, 640, 320, 32);
g.fillRect(352, 640, 320, 32);
g.fillRect(640, 0, 32, 320);
g.fillRect(640, 352, 32, 320);
Maze.walls.add(new Rectangle(0, 0, 672, 32));
Maze.walls.add(new Rectangle(0, 0, 32, 672));
Maze.walls.add(new Rectangle(0, 640, 320, 32));
Maze.walls.add(new Rectangle(352, 640, 320, 32));
Maze.walls.add(new Rectangle(640, 0, 32, 320));
Maze.walls.add(new Rectangle(640, 352, 32, 320));
}
}
now, this works and cycles three stages, but as soon as I change the stage max to 5, it only paints on stages 2 and 4, which are exactly the same. Can anyone tell me what I am doing wrong?
Swing "Timers coalesce events by default." As noted by #HOFE, re-reading your sprite images is likely slowing things down enough to trigger the effect. Instead, read the images into a List<Image> when the program starts.
I am making a circle to circle collision detection program. I can get the balls to move around but when the collision is detected, the balls are quite far overlapped. Any suggestions? Thanks in advance!
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.lang.Math;
public class ShapePanel extends JPanel{
private JButton button, startButton, stopButton;
private JTextField textField;
private JLabel label;
private Timer timer;
private final int DELAY = 10;
ArrayList<Shape> obj = new ArrayList<Shape>();
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ShapePanel());
frame.pack();
frame.setVisible(true);
}
public ShapePanel(){
JPanel controlPanel = new JPanel();
DrawingPanel dpanel = new DrawingPanel();
controlPanel.setPreferredSize(new Dimension(100,400));
button = new JButton("Add Shape");
startButton = new JButton("Start");
stopButton = new JButton("Stop");
textField = new JTextField(2);
label = new JLabel("Count:");
controlPanel.add(button);
controlPanel.add(label);
controlPanel.add(textField);
controlPanel.add(startButton);
controlPanel.add(stopButton);
add(controlPanel);
add(dpanel);
ButtonListener bListen = new ButtonListener();
button.addActionListener(bListen);
startButton.addActionListener(bListen);
stopButton.addActionListener(bListen);
timer = new Timer(DELAY, bListen);
}
private class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
if (e.getSource() == button){
obj.add(new Shape());
if (obj.get(obj.size()-1).y > 200){
obj.get(obj.size()-1).moveY = -obj.get(obj.size()-1).moveY;
}
}else if (e.getSource() == timer){
for (int i = 0; i < obj.size(); i++){
obj.get(i).move();
}
for (int i = 0; i < obj.size(); i++){
for (int j = i + 1; j < obj.size(); j++){
if (Math.sqrt(Math.pow((double)obj.get(i).centerCoordX - (double)obj.get(j).centerCoordX,2)) +
Math.pow((double)obj.get(i).centerCoordY - (double)obj.get(j).centerCoordY,2) <= obj.get(i).radius + obj.get(j).radius){
timer.stop();
}
}
}
}else if (e.getSource() == startButton){
timer.start();
}else if (e.getSource() == stopButton){
timer.stop();
}
repaint();
}
}
private class DrawingPanel extends JPanel{
DrawingPanel(){
setPreferredSize(new Dimension(400,400));
setBackground(Color.pink);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int i = 0; i < obj.size(); i++){
obj.get(i).display(g);
}
}
}
}
import java.awt.*;
import java.util.*;
public class Shape{
public int x, y, width, height, moveX = 1, moveY = 1, centerCoordX, centerCoordY, radius;
private Color colour;
public boolean reverse = false, sameDirection = true;
Random generator = new Random();
public int randomRange(int lo, int hi){
return generator.nextInt(hi-lo)+lo;
}
Shape(){
width = randomRange(30, 50);
if (width % 2 != 0){
width = randomRange(30, 50);
}
height = width;
radius = width/2;
x = randomRange(0, 400-width);
y = randomRange(0, 400-height);
colour = new Color(generator.nextInt(256),generator.nextInt(256),generator.nextInt(256));
}
public void display(Graphics g){
g.setColor(colour);
g.fillOval(x, y, width, height);
}
void move(){
x += moveX;
y += moveY;
centerCoordX = x + width/2;
centerCoordY = y + height/2;
if(x >= 400-width){
moveX = -moveX;
}if(x <= 0){
moveX = -moveX;
}if(y >= 400-height){
moveY = -moveY;
}if (y <= 0){
moveY = -moveY;
}
}
}
So much uncommented code!
The balls are just colliding if their centres are within the sum of the radii. Let r1 and r2 be the ball radii, and x1, y1 the position of the centre of ball1; similarly x2, y2 for ball2.
Measure the square of the distance between the centres as (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1). (Pythagoras).
They have collided if this is less than or equal to (r1 + r2) * (r1 + r2).
The key thing here is that there is no need to compute the square roots which is an expensive computational task.
I'd say it probably due to your circles moving too fast or your time step is too high. Reduce your time step. A better approach is use a physics library like Box2D. Have a look at libgdx, that a java library that has it included.
its discussed a bit in this link
You should check the colision after each move.
for (int i = 0; i < obj.size(); i++)
{
obj.get(i).move();
for (int j = 0; j < obj.size(); j++)
{
if (Math.sqrt(Math.pow((double)obj.get(i).centerCoordX - (double)obj.get(j).centerCoordX,2)) +
Math.pow((double)obj.get(i).centerCoordY - (double)obj.get(j).centerCoordY,2) <= obj.get(i).radius + obj.get(j).radius && i!=j)
{
timer.stop();
}
}
}
You need something like this.
public boolean overlaps (Circle c1, Circle c2) {
float dx = c1.x - c2.x;
float dy = c1.y - c2.y;
float distance = dx * dx + dy * dy;
float radiusSum = c1.radius + c2.radius;
return distance < radiusSum * radiusSum;
}