i want to create a Pong game. I want to move the ball in a way until it touch a wall. if it touch the wall, it go the other way. The problem is that when I start playing, the ball goes in the right way but when it touch the wall, the ball direction reverse but only for one pixel so the ball reverse for 1 pixel and then the direction change angain and it touch the wall again. My code for the moving ball is in the initBall method. Please help me :(
here is my playPanel class :
private int posX = SCREEN_WIDTH / 2;
private int posY;
public Point posMouse = new Point();
private Point posBall = new Point();
private int playPanelWidth;
private int playPanelHeight;
private int padPanelWidth;
private int padPanelHeight;
private int panPanelWidth;
private int panPanelHeight;
private JLabel player1Score = new JLabel("0");
private JLabel ComputerScore = new JLabel("0");
private JPanel panPlayer1;
public JPanel panComputer;
public JPanel padPlayer1;
public JPanel padComputer;
private JButton but_Escape = new JButton("Press escape to continue !");
/*
* Constructor
*/
// ==============================================
public PlayPanel() {
super(new BorderLayout());
setBackground(PANPLAY_COLOR);
panPlayer1 = new JPanel();
panComputer = new JPanel();
padPlayer1 = new JPanel();
padComputer = new JPanel();
padPlayer1.setBackground(Color.DARK_GRAY);
padComputer.setBackground(Color.DARK_GRAY);
padPlayer1.setPreferredSize(PADPANEL_SIZE);
padComputer.setPreferredSize(PADPANEL_SIZE);
panPlayer1.setBackground(PANPLAY_COLOR);
panComputer.setBackground(PANPLAY_COLOR);
panPlayer1.add(padPlayer1);
panComputer.add(padComputer);
add(panPlayer1, BorderLayout.WEST);
add(panComputer, BorderLayout.EAST);
addMouseMotionListener(this);
panPlayer1.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent arg0) {
setPanPanelWidth(arg0.getComponent().getSize().width);
setPanPanelHeight(arg0.getComponent().getSize().height);
}
});
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent arg0) {
setPlayPanelWidth(arg0.getComponent().getSize().width);
setPlayPanelHeight(arg0.getComponent().getSize().height);
}
});
}
/*
* Setters and Getters
*/
// ==============================================
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
public JPanel getPanPlayer1() {
return panPlayer1;
}
public void setPanPlayer1(JPanel panPlayer1) {
this.panPlayer1 = panPlayer1;
}
public JPanel getPanComputer() {
return panComputer;
}
public void setPanComputer(JPanel panComputer) {
this.panComputer = panComputer;
}
public int getPlayPanelHeight() {
return playPanelHeight;
}
public void setPlayPanelHeight(int playPanelHeight) {
this.playPanelHeight = playPanelHeight;
}
public int getPlayPanelWidth() {
return playPanelWidth;
}
public void setPlayPanelWidth(int playPanelWidth) {
this.playPanelWidth = playPanelWidth;
}
public int getPadPanelWidth() {
return padPanelWidth;
}
public void setPadPanelWidth(int padPanelWidth) {
this.padPanelWidth = padPanelWidth;
}
public int getPadPanelHeight() {
return padPanelHeight;
}
public void setPadPanelHeight(int padPanelHeight) {
this.padPanelHeight = padPanelHeight;
}
public int getPanPanelWidth() {
return panPanelWidth;
}
public void setPanPanelWidth(int panPanelWidth) {
this.panPanelWidth = panPanelWidth;
}
public int getPanPanelHeight() {
return panPanelHeight;
}
public void setPanPanelHeight(int panPanelHeight) {
this.panPanelHeight = panPanelHeight;
}
/*
* Add the ball
*/
// ==============================================
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.BLACK);
initBall(g2);
// trait épais
g2.setColor(Color.DARK_GRAY);
g2.setStroke(new BasicStroke(10));
g2.drawLine((getPlayPanelWidth() / 2) - 5, getPlayPanelHeight(),
(getPlayPanelWidth() / 2) - 5, 0);
}
/*
* Init ball
*/
// ==============================================
private void initBall(Graphics2D graphics2d) {
int x = getPosX(), y = getPosY();
boolean backX = false;
boolean backY = false;
Graphics2D g2 = graphics2d;
g2.fillOval(posX, posY, BALL_WIDTH, BALL_HEIGHT);
//posBall.setLocation(posX + BALL_WIDTH, posY + (BALL_HEIGHT / 2));
if (x < 1)
backX = false;
if (x > getWidth() - 50)
backX = true;
if (y < 1)
backY = false;
if (y > getHeight() - 50)
backY = true;
if (!backX)
setPosX(++x);
else {
setPosX(--x);
}
if (!backY)
setPosY(++y);
else
setPosY(--y);
repaint();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void mouseDragged(MouseEvent arg0) {
}
#Override
public void mouseMoved(MouseEvent arg0) {
posMouse.setLocation(arg0.getX(), arg0.getY()
- (getPadPanelHeight() / 2));
padPlayer1.setLocation(getPanPanelWidth() - 15, (int) posMouse.getY());
padComputer.setLocation(5, (int) posMouse.getY());
}
}
So you have:
private void initBall(Graphics2D graphics2d) {
int x = getPosX(), y = getPosY();
boolean backX = false;
boolean backY = false;
in the beginning, so that regardless of which direction the ball is going, booth booleans are set to false every time. Then, you don't have an "Else" when it comes to setting the back option in
if (x < 1)
backX = false;
if (x > getWidth() - 50)
backX = true;
if (y < 1)
backY = false;
if (y > getHeight() - 50)
backY = true;
What is happening is that the ball is moving in the right direction, until it hits a wall (I'm guessing the top wall). then this is called:
if (y > getHeight() - 50)
backY = true;
So then for that iteration the ball goes back because of
if (!backY)
setPosY(++y);
else
setPosY(--y);
But then you set it back to false right away. I suggest you have
private boolean backX = false; //same for backY
outside your method.
Related
I am creating a Space Invaders Game with just one Invader. The images are stuttering and are only visible ~10% of the time. What is wrong with my code?
package spaceinvader;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class spaceInvaders extends JApplet implements KeyListener, ActionListener
{
//Declare components and variables
JPanel mainPanel = new JPanel();
ImageIcon carImage = new ImageIcon("ship.png");
ImageIcon invaderImage = new ImageIcon("invader.png");
int intPosX = 240;
int intPosY = 330;
int intXAmount = 15;
boolean shipMoveLeft = false;
boolean shipMoveRight = false;
Timer shipTimer = new Timer(100,this);
int intBulletX = -50;
int intBulletY = -50;
boolean bulletMove = false;
boolean bulletActive = false;
Timer bulletTimer = new Timer(50,this);
int intInvaderX = 0;
int intInvaderY = 0;
int invaderXAmount = 10;
boolean invaderMove = true;
Timer invaderTimer= new Timer(1000,this);
public void init()
{
addKeyListener(this);
setFocusable(true);
resize(600,400);
setContentPane(mainPanel);
shipTimer.start();
bulletTimer.start();
invaderTimer.start();
}
public void actionPerformed(ActionEvent e)
{
requestFocus();
if(shipMoveLeft)
intPosX += intXAmount;
else if(shipMoveRight)
intPosX -= intXAmount;
if(bulletMove && bulletActive){
intBulletY -= 15;
if(intBulletY <= -50){
bulletMove = false;
bulletActive = false;
}
}
if(invaderMove){
intInvaderX += invaderXAmount;
if(intInvaderX > getWidth() - 60 || intInvaderX < 0){
intInvaderY += 40;
invaderXAmount *= -1;
}
}
repaint();
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if (key == 37){
shipMoveRight = true;
}
else if (key == 39){
shipMoveLeft = true;
}
else if (key == 32){
if(bulletActive == false){
intBulletX = intPosX;
intBulletY = intPosY;
}
bulletMove = true;
bulletActive = true;
}
}
public void keyReleased(KeyEvent e)
{
shipMoveLeft = false;
shipMoveRight = false;
}
public void keyTyped(KeyEvent e)
{
}
public void paint(Graphics gr)
{
super.paint(gr);
gr.setColor(Color.red);
gr.fillOval(intBulletX, intBulletY, 10, 25);
carImage.paintIcon(this,gr, intPosX, intPosY); //Draw image in new spot
invaderImage.paintIcon(this,gr, intInvaderX, intInvaderY);
}
}
So there are a number of issues which jump out immediately...
Applets are a dead end, most browsers will actively block them and/or have dropped support for the plugin
You're adding a JPanel to the applet, but overriding the applet's paint method, because of the way painting can work, the panel can be painted independently of the applet, causing it to paint over whatever you might have painted
You don't need multiple timers, you just need to have better delta values (smaller been faster)
KeyListener is a poor choice for detecting keyboard input, it's rather low level and has focus related issues which are easily overcome by using the Key Bindings API
I'd start by having a look at Performing Custom Painting, Painting in AWT and Swing and How to Use Key Bindings for more details.
So how would you start fixing it? Start by using a JPanel as you basic container, override it's paintComponent and place all your paint logic here.
Use a single Timer to manage the updates
There are any number of approaches you can take, but I'd start with defining some contracts that define what can go on in the game
public interface GameSpace extends ImageObserver {
public Dimension getGameSpace();
public boolean hasInput(Input input);
}
public interface Entity {
public void paint(GameSpace gameSpace, Graphics2D g2d);
public boolean update(GameSpace gameSpace);
public Rectangle getBounds();
}
public abstract class AbstractEntity implements Entity {
private int x;
private int y;
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
protected abstract int getWidth();
protected abstract int getHeight();
public Rectangle getBounds() {
return new Rectangle(getX(), getY(), getWidth(), getHeight());
}
}
public abstract class AbstractImageEntity extends AbstractEntity {
protected abstract BufferedImage getImage();
#Override
protected int getWidth() {
return getImage().getWidth();
}
#Override
protected int getHeight() {
return getImage().getHeight();
}
}
This separates some of management of key elements, allowing for a more flexible design. You might have a lot more entities, one's which could move, ones which could not, some which are painted, some which are not, but all which provide support for the core engine to get work done.
Once you have that you can start defining some core entities you need
public class ShipEntity extends AbstractImageEntity {
private BufferedImage ship;
public ShipEntity(GameSpace gameSpace) throws IOException {
ship = ImageIO.read(getClass().getResource("/resources/ship.png"));
setY(gameSpace.getGameSpace().height - getBounds().height);
setX((gameSpace.getGameSpace().width - getBounds().width) / 2);
}
#Override
public BufferedImage getImage() {
return ship;
}
#Override
public void paint(GameSpace gameSpace, Graphics2D g2d) {
g2d.drawImage(ship, getX(), getY(), gameSpace);
}
#Override
public boolean update(GameSpace gameSpace) {
int x = getX();
if (gameSpace.hasInput(Input.LEFT)) {
x -= 2;
}
if (gameSpace.hasInput(Input.RIGHT)) {
x += 2;
}
if (x < 0) {
x = 0;
} else if (x + getWidth() > gameSpace.getGameSpace().width) {
x = gameSpace.getGameSpace().width - getWidth();
}
setX(x);
return true;
}
}
public class InvaderEntity extends AbstractImageEntity {
private BufferedImage invader;
public InvaderEntity() throws IOException {
invader = ImageIO.read(getClass().getResource("/resources/Invader.png"));
}
#Override
protected BufferedImage getImage() {
return invader;
}
#Override
public void paint(GameSpace gameSpace, Graphics2D g2d) {
g2d.drawImage(invader, getX(), getY(), gameSpace);
}
#Override
public boolean update(GameSpace gameSpace) {
return true;
}
}
public class ProjectileEntity extends AbstractEntity {
private int delta;
public ProjectileEntity(int delta) {
this.delta = delta;
}
#Override
protected int getWidth() {
return 10;
}
#Override
protected int getHeight() {
return 10;
}
#Override
public void paint(GameSpace gameSpace, Graphics2D g2d) {
g2d.setColor(Color.RED);
int width = getWidth();
int height = getHeight();
g2d.fillOval(getX() - width / 2, getY() - height / 2, width, height);
}
#Override
public boolean update(GameSpace gameSpace) {
int y = getY() + delta;
setY(getY() + delta);
return y + getHeight() >= 0 && y + getHeight() <= gameSpace.getGameSpace().height;
}
}
Basically, they contain the logic required for getting their jobs done.
Finally, you need to setup the actual game UI
public class GamePane extends JPanel implements GameSpace {
private Set<Input> inputs;
private Entity playerEntity;
private List<Entity> projectileEntities;
private List<Entity> invaderEntities;
private long timeOfLastProjectile = -1;
public GamePane() throws IOException {
setBackground(Color.BLACK);
inputs = new HashSet<>(2);
playerEntity = new ShipEntity(this);
projectileEntities = new ArrayList<>(25);
invaderEntities = new ArrayList<>(25);
InvaderEntity invader = new InvaderEntity();
invader.setX((getGameSpace().width - invader.getBounds().width) / 2);
invader.setY((getGameSpace().height - invader.getBounds().height) / 2);
invaderEntities.add(invader);
addKeyBinding(Input.LEFT, "left", KeyEvent.VK_LEFT);
addKeyBinding(Input.RIGHT, "right", KeyEvent.VK_RIGHT);
addKeyBinding(Input.SPACE, "space", KeyEvent.VK_SPACE);
Timer timer = new Timer(15, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateState();
processCollisions();
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
protected void updateState() {
playerEntity.update(this);
if (hasInput(Input.SPACE)) {
long time = System.currentTimeMillis() - timeOfLastProjectile;
if (time < 0 || time > 1000) {
timeOfLastProjectile = System.currentTimeMillis();
Rectangle bounds = playerEntity.getBounds();
ProjectileEntity projectile = new ProjectileEntity(-1);
int x = bounds.x + ((bounds.width - projectile.getWidth()) / 2);
int y = bounds.y - projectile.getHeight();
projectile.setX(x);
projectile.setY(y);
projectileEntities.add(projectile);
}
}
for (Entity entity : invaderEntities) {
entity.update(this);
}
List<Entity> outOfBounds = new ArrayList<>(25);
for (Entity entity : projectileEntities) {
if (!entity.update(this)) {
outOfBounds.add(entity);
}
}
projectileEntities.removeAll(outOfBounds);
}
protected void processCollisions() {
Set<Entity> hitInvaders = new HashSet<>(25);
Set<Entity> hitProjectiles = new HashSet<>(25);
for (Entity invader : invaderEntities) {
for (Entity projectile : projectileEntities) {
if (projectile.getBounds().intersects(invader.getBounds())) {
// Maybe lots of cool explosiions
hitInvaders.add(invader);
hitProjectiles.add(projectile);
}
}
}
invaderEntities.removeAll(hitInvaders);
projectileEntities.removeAll(hitProjectiles);
}
protected void addKeyBinding(Input input, String name, int virtualKey) {
ActionMap am = getActionMap();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(virtualKey, 0, false), name + ".pressed");
im.put(KeyStroke.getKeyStroke(virtualKey, 0, true), name + ".released");
am.put(name + ".pressed", new KeyAction(inputs, input, true));
am.put(name + ".released", new KeyAction(inputs, input, false));
}
#Override
public Dimension getGameSpace() {
return getPreferredSize();
}
#Override
public boolean hasInput(Input input) {
return inputs.contains(input);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
playerEntity.paint(this, g2d);
g2d.dispose();
for (Entity entity : invaderEntities) {
g2d = (Graphics2D) g.create();
entity.paint(this, g2d);
g2d.dispose();
}
for (Entity entity : projectileEntities) {
g2d = (Graphics2D) g.create();
entity.paint(this, g2d);
g2d.dispose();
}
}
}
public class KeyAction extends AbstractAction {
private Input input;
private Set<Input> inputs;
private boolean pressed;
public KeyAction(Set<Input> inputs, Input input, boolean pressed) {
this.input = input;
this.inputs = inputs;
this.pressed = pressed;
}
#Override
public void actionPerformed(ActionEvent e) {
if (pressed) {
inputs.add(input);
} else {
inputs.remove(input);
}
}
}
Now you could go a little further and generate an "engine" class which controls the entities and performs all the required updating, but I'm lazy ;)
That's a really rough idea of some the basic concepts you need to develop to be able to move forward, hope it helps
Okay, so I am trying to create a simple game where you shoot a missile and if it hits a wall it has to bounce back expect for the bottom wall were it will inactivate the missile to allow me to shoot a new missile.
import java.awt.*;
public class Project2{
public static final int PANEL_WIDTH = 300;
public static final int PANEL_HEIGHT = 300;
public static final int SLEEP_TIME = 50;
public static final Color SHOOTER_COLOR = Color.RED;
public static final Color BACKGROUND_COLOR = Color.WHITE;
public static final int SHOOTER_SIZE = 20; //diameter of the shooter
public static final int GUN_SIZE = 10; //length og the gun
public static final int SHOOTER_POSITION_Y = PANEL_HEIGHT - SHOOTER_SIZE;
public static final int SHOOTER_INITIAL_POSITION_X = 150;
public static int shooterPositionX;
public static int gunPositionX;
public static int gunPositionY;
public static int targetPositionX;
public static final Color TARGET_COLOR = Color.BLUE;
public static final int TARGET_POSITION_Y = 50;
public static final int TARGET_SIZE = 20;
public static final int KEY_SPACE =32;
public static final int KEY_PAGE_UP = 33;
public static final int KEY_HOME = 36;
public static final int KEY_LEFT_ARROW = 37;
public static final int KEY_UP_ARROW = 38;
public static final int KEY_RIGHT_ARROW = 39;
public static final int KEY_DOWN_ARROW = 40;
public static double missilePositionX;
public static double missilePositionY;
public static double missileDeltaX;
public static double missileDeltaY;
public static boolean missileActive;
public static final Color MISSILE_COLOR = Color.BLACK;
public static final int MISSILE_SIZE =2;
public static final double MISSILE_SPEED =1.0;
public static int hitCount;
public static final int TARGET_DELTA_X= 1;
public static int targetDeltaX;
// public static final Random.nextDouble();
public static void initialize(){
shooterPositionX = SHOOTER_INITIAL_POSITION_X;
gunPositionX = 0;
gunPositionY = GUN_SIZE;
targetPositionX = 150;
missileActive = false;
hitCount = 0;
targetDeltaX = 0;
}
public static void main(String[] args) {
DrawingPanel panel = new DrawingPanel(PANEL_WIDTH, PANEL_HEIGHT);
Graphics g = panel.getGraphics( );
initialize();
startGame(panel, g);
}
public static void drawAll(Graphics g){
g.setColor(Color.BLACK);
g.drawString("Project 2 by JR", 10, 15); // fix ""
g.drawString("Hits: " + hitCount, 10, 30);
// for(int i=0, i<=hitCount; i++){
//
// }
// Hits: followed by a number of stars corresponding to the hit count.
//Do not do this by calling g.drawString in a loop. Instead, make a single string with a
//for loop, appending the appropriate number of stars. Then call g.drawString once.
drawShooter(g, SHOOTER_COLOR);
drawTarget(g, TARGET_COLOR);
}
public static void startGame(DrawingPanel panel, Graphics g) {
for (int i = 0; i <= 10000; i++) {
panel.sleep(SLEEP_TIME);
handleKeys(panel, g);
// moveTarget(g);
drawAll(g);
moveMissile(g);
}
}
public static void drawShooter(Graphics g, Color c){
g.setColor(c);
g.fillOval(shooterPositionX-SHOOTER_SIZE/2, SHOOTER_POSITION_Y-SHOOTER_SIZE, SHOOTER_SIZE, SHOOTER_SIZE);
g.drawLine(shooterPositionX, SHOOTER_POSITION_Y-SHOOTER_SIZE, shooterPositionX+gunPositionX, SHOOTER_POSITION_Y-SHOOTER_SIZE - GUN_SIZE);
}
public static void drawTarget(Graphics g, Color c){
g.setColor(c);
g.fillOval(targetPositionX-TARGET_SIZE/2, TARGET_POSITION_Y-TARGET_SIZE, TARGET_SIZE, TARGET_SIZE);
g.drawLine(targetPositionX-TARGET_SIZE, TARGET_POSITION_Y+TARGET_SIZE/2, targetPositionX+TARGET_SIZE, TARGET_POSITION_Y+TARGET_SIZE/2);
}
public static void moveShooter(Graphics g, int deltaX){
drawShooter(g, BACKGROUND_COLOR);
shooterPositionX += deltaX;
drawShooter(g, SHOOTER_COLOR);
//does not allow you to move any part of the shooter off the screen.
}
public static void handleKeys(DrawingPanel panel, Graphics g){
int keyCode = panel.getKeyCode();
if (keyCode == KEY_SPACE)
reset(g);
else if (keyCode == KEY_RIGHT_ARROW)
moveShooter(g,1);
else if (keyCode == KEY_LEFT_ARROW)
moveShooter(g,-1);
else if (keyCode == KEY_HOME)
moveGun(g,1);
else if (keyCode == KEY_PAGE_UP)
moveGun(g,-1);
else if(keyCode == KEY_UP_ARROW)
shootMissile(g);
}
public static void reset(Graphics g){
g.setColor(BACKGROUND_COLOR);
g.fillRect(0,0, PANEL_WIDTH, PANEL_HEIGHT);
initialize();
}
public static void moveGun(Graphics g, int deltaX){
drawShooter(g, BACKGROUND_COLOR);
gunPositionX += deltaX;
drawShooter(g, SHOOTER_COLOR);
//Do not let gunPositionX have an absolute value larger than SHOOTER_SIZE.
}
public static void shootMissile(Graphics g){
if(missileActive == false){
missileActive = true;
missilePositionX = shooterPositionX;
missilePositionY = SHOOTER_POSITION_Y-SHOOTER_SIZE;
missileDeltaX = 0;
missileDeltaY = 0;
missilePositionX += missileDeltaX;
missilePositionY += missileDeltaY;
}
}
public static void moveMissile(Graphics g){
if(missileActive){
drawMissile(g, BACKGROUND_COLOR);
missilePositionX += missileDeltaX;
missilePositionY += missileDeltaY;
drawMissile(g, MISSILE_COLOR);
if(missilePositionY <= 0){
missileDeltaY = -Math.abs(missileDeltaY);
missilePositionY += missileDeltaY;
}
else if(missilePositionX >= 300){
missilePositionX += missileDeltaX;
}
else if(missilePositionX <=0){
missileDeltaX = -Math.abs(missileDeltaX);
missilePositionX += missileDeltaX;
}
else if(missilePositionY >= 300){
drawMissile(g, BACKGROUND_COLOR);
missileActive = false;
}
if( detectHitTarget((int)missilePositionX, (int)missilePositionY, (int)MISSILE_SIZE/2, targetPositionX, TARGET_POSITION_Y, TARGET_SIZE/2)){
hitCount ++;
drawMissile(g, BACKGROUND_COLOR);//erase the missile;
missileActive = false;
}
}
}
public static void drawMissile(Graphics g, Color c){
g.setColor(c);
g.fillOval((int)missilePositionX, (int)missilePositionY, MISSILE_SIZE, MISSILE_SIZE);
missileDeltaY = - gunPositionY * MISSILE_SPEED;
missileDeltaX = gunPositionX * MISSILE_SPEED;
}
public static boolean detectHitTarget(int x1, int y1, int r1, int x2, int y2, int r2){
if(Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)) <= r1 + r2){
return true;
}else{
return false;}
}
public static void moveTarget(Graphics g){
// drawTarget(g, BACKGROUND_COLOR);
// targetPositionX += targetDeltaX;
// if(targetPositionX >= 0){
// targetPositionX = +Math.abs(targetDelta);
// }
// else if(targetPositionX <=300){
// targetPositionX = -Math.abs(targetDelta);
// }
// if(Random >= .98){
// targetDeltaX = 0;
// }
// else if(Random >= .96){
// targetDeltaX =1;
// }
// else if(Random >= .94){
// targetDleta = -1;
// }
}
}
so far the ball is just getting 'stuck' to the top wall or not even getting 'stuck' in the case of the side walls just going off the panel, instead of bouncing off and I can't seem to figure it out.
Drawing Panel
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.ArrayList;
public class DrawingPanel implements ActionListener {
private static final String versionMessage =
"Drawing Panel version 1.1, January 25, 2015";
private static final int DELAY = 100; // delay between repaints in millis
private static final boolean PRETTY = false; // true to anti-alias
private static boolean showStatus = false;
private static final int MAX_KEY_BUF_SIZE = 10;
private int width, height; // dimensions of window frame
private JFrame frame; // overall window frame
private JPanel panel; // overall drawing surface
private BufferedImage image; // remembers drawing commands
private Graphics2D g2; // graphics context for painting
private JLabel statusBar; // status bar showing mouse position
private volatile MouseEvent click; // stores the last mouse click
private volatile boolean pressed; // true if the mouse is pressed
private volatile MouseEvent move; // stores the position of the mouse
private ArrayList<KeyInfo> keys;
// construct a drawing panel of given width and height enclosed in a window
public DrawingPanel(int width, int height) {
this.width = width;
this.height = height;
keys = new ArrayList<KeyInfo>();
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
statusBar = new JLabel(" ");
statusBar.setBorder(BorderFactory.createLineBorder(Color.BLACK));
statusBar.setText(versionMessage);
panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
panel.setBackground(Color.WHITE);
panel.setPreferredSize(new Dimension(width, height));
panel.add(new JLabel(new ImageIcon(image)));
click = null;
move = null;
pressed = false;
// listen to mouse movement
MouseInputAdapter listener = new MouseInputAdapter() {
public void mouseMoved(MouseEvent e) {
pressed = false;
move = e;
if (showStatus)
statusBar.setText("moved (" + e.getX() + ", " + e.getY() + ")");
}
public void mousePressed(MouseEvent e) {
pressed = true;
move = e;
if (showStatus)
statusBar.setText("pressed (" + e.getX() + ", " + e.getY() + ")");
}
public void mouseDragged(MouseEvent e) {
pressed = true;
move = e;
if (showStatus)
statusBar.setText("dragged (" + e.getX() + ", " + e.getY() + ")");
}
public void mouseReleased(MouseEvent e) {
click = e;
pressed = false;
if (showStatus)
statusBar.setText("released (" + e.getX() + ", " + e.getY() + ")");
}
public void mouseEntered(MouseEvent e) {
// System.out.println("mouse entered");
panel.requestFocus();
}
};
panel.addMouseListener(listener);
panel.addMouseMotionListener(listener);
new DrawingPanelKeyListener();
g2 = (Graphics2D)image.getGraphics();
g2.setColor(Color.BLACK);
if (PRETTY) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(1.1f));
}
frame = new JFrame("Drawing Panel");
frame.setResizable(false);
try {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // so that this works in an applet
} catch (Exception e) {}
frame.getContentPane().add(panel);
frame.getContentPane().add(statusBar, "South");
frame.pack();
frame.setVisible(true);
toFront();
frame.requestFocus();
// repaint timer so that the screen will update
new Timer(DELAY, this).start();
}
public void showMouseStatus(boolean f) {
showStatus = f;
}
public void addKeyListener(KeyListener listener) {
panel.addKeyListener(listener);
panel.requestFocus();
}
// used for an internal timer that keeps repainting
public void actionPerformed(ActionEvent e) {
panel.repaint();
}
// obtain the Graphics object to draw on the panel
public Graphics2D getGraphics() {
return g2;
}
// set the background color of the drawing panel
public void setBackground(Color c) {
panel.setBackground(c);
}
// show or hide the drawing panel on the screen
public void setVisible(boolean visible) {
frame.setVisible(visible);
}
// makes the program pause for the given amount of time,
// allowing for animation
public void sleep(int millis) {
panel.repaint();
try {
Thread.sleep(millis);
} catch (InterruptedException e) {}
}
// close the drawing panel
public void close() {
frame.dispose();
}
// makes drawing panel become the frontmost window on the screen
public void toFront() {
frame.toFront();
}
// return panel width
public int getWidth() {
return width;
}
// return panel height
public int getHeight() {
return height;
}
// return the X position of the mouse or -1
public int getMouseX() {
if (move == null) {
return -1;
} else {
return move.getX();
}
}
// return the Y position of the mouse or -1
public int getMouseY() {
if (move == null) {
return -1;
} else {
return move.getY();
}
}
// return the X position of the last click or -1
public int getClickX() {
if (click == null) {
return -1;
} else {
return click.getX();
}
}
// return the Y position of the last click or -1
public int getClickY() {
if (click == null) {
return -1;
} else {
return click.getY();
}
}
// return true if a mouse button is pressed
public boolean mousePressed() {
return pressed;
}
public synchronized int getKeyCode() {
if (keys.size() == 0)
return 0;
return keys.remove(0).keyCode;
}
public synchronized char getKeyChar() {
if (keys.size() == 0)
return 0;
return keys.remove(0).keyChar;
}
public synchronized int getKeysSize() {
return keys.size();
}
private synchronized void insertKeyData(char c, int code) {
keys.add(new KeyInfo(c,code));
if (keys.size() > MAX_KEY_BUF_SIZE) {
keys.remove(0);
// System.out.println("Dropped key");
}
}
private class KeyInfo {
public int keyCode;
public char keyChar;
public KeyInfo(char keyChar, int keyCode) {
this.keyCode = keyCode;
this.keyChar = keyChar;
}
}
private class DrawingPanelKeyListener implements KeyListener {
int repeatCount = 0;
public DrawingPanelKeyListener() {
panel.addKeyListener(this);
panel.requestFocus();
}
public void keyPressed(KeyEvent event) {
// System.out.println("key pressed");
repeatCount++;
if ((repeatCount == 1) || (getKeysSize() < 2))
insertKeyData(event.getKeyChar(),event.getKeyCode());
}
public void keyTyped(KeyEvent event) {
}
public void keyReleased(KeyEvent event) {
repeatCount = 0;
}
}
}
Your drawMissile method which is called inside moveMissile method everytime it is called it is re-initializing the missileDeltaY and missileDeltaX variables.
missileDeltaY = - gunPositionY * MISSILE_SPEED;
missileDeltaX = gunPositionX * MISSILE_SPEED;
So no matter what calculations take place in the rest body of the moveMissile method, those variables will take their default values hence no change of the trajectory when hitting the boundaries.
I have made some changes in your methods to help you figure out the solution, it looks like it is working if you shoot the missile to hit the left boundary
shootMissile
public static void shootMissile(Graphics g){
if(missileActive == false){
missileActive = true;
missilePositionX = shooterPositionX;
missilePositionY = SHOOTER_POSITION_Y-SHOOTER_SIZE;
missileDeltaX = 0;
missileDeltaY = 0;
missilePositionX += missileDeltaX;
missilePositionY += missileDeltaY;
missileDeltaY = - gunPositionY * MISSILE_SPEED;
missileDeltaX = gunPositionX * MISSILE_SPEED;
}
}
moveMissile
public static void moveMissile(Graphics g){
if(missileActive){
drawMissile(g, BACKGROUND_COLOR);
missilePositionX += missileDeltaX;
missilePositionY += missileDeltaY;
drawMissile(g, MISSILE_COLOR);
if(missilePositionY <= 0){
missileDeltaY = Math.abs(missileDeltaY);
missilePositionY += missileDeltaY;
}
if(missilePositionX >= 300){
missilePositionX += -Math.abs(missileDeltaX);
}
if(missilePositionX <=0){
missileDeltaX = Math.abs(missileDeltaX);
missilePositionX += missileDeltaX;
}
if(missilePositionY >= 300){
drawMissile(g, BACKGROUND_COLOR);
missileActive = false;
}
if( detectHitTarget((int)missilePositionX, (int)missilePositionY, (int)MISSILE_SIZE/2, targetPositionX, TARGET_POSITION_Y, TARGET_SIZE/2)){
hitCount ++;
drawMissile(g, BACKGROUND_COLOR);//erase the missile;
missileActive = false;
}
}
}
drawMissile
public static void drawMissile(Graphics g, Color c){
g.setColor(c);
g.fillOval((int)missilePositionX, (int)missilePositionY, MISSILE_SIZE, MISSILE_SIZE);
}
Basically, all that shows up is a JFrame with the black JPanel inside but no Ball/polygon anywhere. It's really annoying me now and I can't see the reason why. Any help greatly appreciated.
EDIT: Added code. Sorry for posting to Github, didn't know it was frowned upon.
public class Board extends JFrame {
private int width = 800;
private int height = 1000;
private int currentKeyCode = 0;
private boolean keyHeldDown = false;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Board b = new Board();
b.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Board() {
setSize(width, height);
setTitle("Drop");
setBackground(Color.BLACK);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
currentKeyCode = KeyEvent.VK_RIGHT;
keyHeldDown = true;
System.out.println("Right + 10");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
currentKeyCode = KeyEvent.VK_LEFT;
keyHeldDown = true;
System.out.println("Left + 10");
}
if (e.getKeyCode() == KeyEvent.VK_P) {
currentKeyCode = KeyEvent.VK_P;
keyHeldDown = true;
System.out.println("Pause");
}
}
#Override
public void keyReleased(KeyEvent e) {
keyHeldDown = false;
}
});
setContentPane(new Panel(this));
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
executor.scheduleAtFixedRate(new RepaintBoard(this), 0L, 20L, TimeUnit.MILLISECONDS);
}
#Override
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
#Override
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
private class RepaintBoard implements Runnable {
final Board board;
public RepaintBoard(Board board) {
this.board = board;
}
#Override
public void run() {
board.repaint();
}
}
}
class Panel extends JComponent {
Ball ball;
private Board board;
public Panel(Board board) {
this.board = board;
ball = new Ball();
}
#Override
public void paint(Graphics g1) {
Graphics2D g = (Graphics2D) g1;
g.setColor(Color.BLACK);
g.drawRect(0, 0, board.getWidth(), board.getHeight());
g.drawPolygon(ball);
}
}
class Ball extends Polygon {
private int radius = 5;
private Point loc;
private int[] xPos = new int[radius * 2 + 1];
private int[] yPos = new int[radius * 2 + 1];
public Ball() {
for (int i = -radius, j = 0; i <= radius; i++, j++) {
xPos[j] = i;
yPos[j] = i;
}
new Ball(xPos, yPos, radius * 2 + 1, 100, 100);
}
public Ball(int[] xPos, int[] yPos, int points, int x, int y) {
super(xPos, yPos, points);
loc = new Point(x, y);
for (int i : xPos) {
System.out.println(i);
}
}
}
Don't have Ball extends Polygon
Put a drawBall(Grapchics g) {} method in the Ball class, and do your ball painting in there.
call the drawBall method in the paint
ball.drawBall(g);
Don't override paint, instead override paintComponent on the panel, and don't forget to call super.paintComponent
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
This new Ball(xPos, yPos, radius * 2 + 1, 100, 100); in your constructor does absolutely nothing. You should instead just use the second constructor, and create the ball with that constructor. Each ball should be different, so a no-arg constructor is pointless
I want to creat a circle in on a panel which appears and dissapears every 2 seconds.
Here is that i have:
public class Board extends JPanel implements ActionListener {
private final int DELAY = 2000;
private Timer timer;
/*
* constructor
*/
public Board() {
setFocusable(true);
initGame();
}
/*
* initialize board
*/
public void initGame() {
timer = new Timer(DELAY, this);
timer.start();
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.gray);
// draw an oval starting at 20,20 with a width and height of 100 and
// fill it
g.drawOval(20, 20, 100, 100);
g.fillOval(20, 20, 100, 100);
g.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}
thank you guys. Now I wanna control my circle. But again something is wrong and it is not moving as I want.
here are new methods:
private boolean left = false;
private boolean right = true;
private boolean up = false;
private boolean down = false;
private Timer timer;
public int x = 20;
public int y = 20;
public int x2 = 100;
public int y2 = 100;
...
public void paint(Graphics g) {
super.paint(g);
if (drawCircle) {
g.setColor(Color.gray);
// draw an oval starting at 20,20 with a width and height of 100 and
// fill it
g.drawOval(x, y, x2, y2);
g.fillOval(x, y, x2, y2);
}
// removes native non-Java recourses
g.dispose();
}
public void move() {
if (left) {
x -= 5;
}
if (right) {
x += 5;
}
if (up) {
y -= 5;
}
if (down) {
y += 5;
}
}
#Override
public void actionPerformed(ActionEvent e) {
move();
repaint();
}
private class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if ((key == KeyEvent.VK_LEFT) && (!right)) {
left = true;
up = false;
down = false;
}
if ((key == KeyEvent.VK_RIGHT) && (!left)) {
right = true;
up = false;
down = false;
}
if ((key == KeyEvent.VK_UP) && (!down)) {
up = true;
right = false;
left = false;
}
if ((key == KeyEvent.VK_DOWN) && (!up)) {
down = true;
right = false;
left = false;
}
}
}
/****/
Solved , i just added
addKeyListener(new TAdapter());
to my Board constructor!
You just need to have your Timer modify some state. Try something like this:
private boolean drawCircle = false;
public void actionPerformed(ActionEvent e) {
drawCircle = !drawCircle;
repaint();
}
public void paintComponent(Graphics g) {
//...
if ( drawCircle ) {
g.setColor(Color.gray);
//...
}
}
Aren't you supposed to formulate the question... as a question?
Anyway, add a boolean to your class, toggle it on each action event, and paint the oval only if it is true.
Edit/Notes:
- Override paintComponent instead of paint
- Don't dispose of a Graphics you haven't created. Either drop the line, or use g.create() to make a copy. See http://java.sun.com/products/jfc/tsc/articles/swing2d/ for details.
I'm trying to create a custom extension of BasicSliderUI. I'm just trying to make the thumb a circle (note I'm in the Windows L&F). I've created a very simple implementation that just calls g.drawOval, but whenever I drag it, it leaves a "trail" behind. Any ideas why this is?
thanks,
Jeff
You need to call repaint on the whole thing, you cant just draw the oval on top of it. Swing will by default only repaint what needs to be repainted, which usually isn't the whole control. When are you drawing the circle?
If you want to get rid of "trail" when you drag you should write your custom TrackListener and control trumb position related to mouse move.
Look at my implementation:
public class LightSliderUI extends BasicSliderUI{
private final Color rangeColor = Color.BLUE;
private final BasicStroke stroke = new BasicStroke(2f);
private transient boolean upperDragging;
public LightSliderUI(JSlider b) {
super(b);
}
public static ComponentUI createUI(JComponent c) {
return new LightSliderUI((JSlider)c);
}
#Override
protected void calculateThumbSize() {
super.calculateThumbSize();
thumbRect.setSize(thumbRect.width, thumbRect.height);
}
/** Creates a listener to handle track events in the specified slider.*/
#Override
protected TrackListener createTrackListener(JSlider slider) {
return new RangeTrackListener();
}
#Override
protected void calculateThumbLocation() {
// Call superclass method for lower thumb location.
super.calculateThumbLocation();
// Adjust upper value to snap to ticks if necessary.
if (slider.getSnapToTicks()) {
int upperValue = slider.getValue() + slider.getExtent();
int snappedValue = upperValue;
int majorTickSpacing = slider.getMajorTickSpacing();
int minorTickSpacing = slider.getMinorTickSpacing();
int tickSpacing = 0;
if (minorTickSpacing > 0) {
tickSpacing = minorTickSpacing;
} else if (majorTickSpacing > 0) {
tickSpacing = majorTickSpacing;
}
if (tickSpacing != 0) {
// If it's not on a tick, change the value
if ((upperValue - slider.getMinimum()) % tickSpacing != 0) {
float temp = (float)(upperValue - slider.getMinimum()) / (float)tickSpacing;
int whichTick = Math.round(temp);
snappedValue = slider.getMinimum() + (whichTick * tickSpacing);
}
if (snappedValue != upperValue) {
slider.setExtent(snappedValue - slider.getValue());
}
}
}
// Calculate upper thumb location. The thumb is centered over its
// value on the track.
if (slider.getOrientation() == JSlider.HORIZONTAL) {
int upperPosition = xPositionForValue(slider.getValue() + slider.getExtent());
thumbRect.x = upperPosition - (thumbRect.width / 2);
thumbRect.y = trackRect.y;
} else {
int upperPosition = yPositionForValue(slider.getValue() + slider.getExtent());
thumbRect.x = trackRect.x;
thumbRect.y = upperPosition - (thumbRect.height / 2);
}
slider.repaint();
}
/** Returns the size of a thumb.
* Parent method not use size from LaF
* #return size of trumb */
#Override
protected Dimension getThumbSize() {
return Dimensions.getSliderThumbSize();
}
private Shape createThumbShape(int width, int height) {
Ellipse2D shape = new Ellipse2D.Double(0, 0, width, height);
return shape;
}
#Override
public void paintTrack(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Stroke old = g2d.getStroke();
g2d.setStroke(stroke);
g2d.setPaint(Colors.TEXT_STEEL);
Color oldColor = Colors.TEXT_STEEL;
Rectangle trackBounds = trackRect;
if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
g2d.drawLine(trackRect.x, trackRect.y + trackRect.height / 2,
trackRect.x + trackRect.width, trackRect.y + trackRect.height / 2);
int lowerX = thumbRect.width / 2;
int upperX = thumbRect.x + (thumbRect.width / 2);
int cy = (trackBounds.height / 2) - 2;
g2d.translate(trackBounds.x, trackBounds.y + cy);
g2d.setColor(rangeColor);
g2d.drawLine(lowerX - trackBounds.x, 2, upperX - trackBounds.x, 2);
g2d.translate(-trackBounds.x, -(trackBounds.y + cy));
g2d.setColor(oldColor);
}
g2d.setStroke(old);
}
/** Overrides superclass method to do nothing. Thumb painting is handled
* within the <code>paint()</code> method.*/
#Override
public void paintThumb(Graphics g) {
Rectangle knobBounds = thumbRect;
int w = knobBounds.width;
int h = knobBounds.height;
Graphics2D g2d = (Graphics2D) g.create();
Shape thumbShape = createThumbShape(w - 1, h - 1);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.translate(knobBounds.x, knobBounds.y);
g2d.setColor(Color.WHITE);
g2d.fill(thumbShape);
g2d.setColor(Colors.BIOLIN_BLUE_TINT);
g2d.draw(thumbShape);
g2d.dispose();
}
/** Listener to handle model change events. This calculates the thumb
* locations and repaints the slider if the value change is not caused by dragging a thumb.*/
public class ChangeHandler implements ChangeListener {
#Override
public void stateChanged(ChangeEvent arg0) {
calculateThumbLocation();
slider.repaint();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
JSlider slider = new JSlider(0, 100);
slider.setPaintTicks(true);
slider.setUI(new LightSliderUI(slider));
frame.add(slider);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
/** Listener to handle mouse movements in the slider track.*/
public class RangeTrackListener extends TrackListener {
#Override
public void mouseClicked(MouseEvent e) {
if (!slider.isEnabled()) {
return;
}
currentMouseX -= thumbRect.width / 2; // Because we want the mouse location correspond to middle of the "thumb", not left side of it.
moveUpperThumb();
}
public void mousePressed(MouseEvent e) {
if (!slider.isEnabled()) {
return;
}
currentMouseX = e.getX();
currentMouseY = e.getY();
if (slider.isRequestFocusEnabled()) {
slider.requestFocus();
}
boolean upperPressed = false;
if (slider.getMinimum() == slider.getValue()) {
if (thumbRect.contains(currentMouseX, currentMouseY)) {
upperPressed = true;
}
} else {
if (thumbRect.contains(currentMouseX, currentMouseY)) {
upperPressed = true;
}
}
if (upperPressed) {
switch (slider.getOrientation()) {
case JSlider.VERTICAL:
offset = currentMouseY - thumbRect.y;
break;
case JSlider.HORIZONTAL:
offset = currentMouseX - thumbRect.x;
break;
}
//upperThumbSelected = true;
upperDragging = true;
return;
}
upperDragging = false;
}
#Override
public void mouseReleased(MouseEvent e) {
upperDragging = false;
slider.setValueIsAdjusting(false);
super.mouseReleased(e);
}
#Override
public void mouseDragged(MouseEvent e) {
if (!slider.isEnabled()) {
return;
}
currentMouseX = e.getX();
currentMouseY = e.getY();
if (upperDragging) {
slider.setValueIsAdjusting(true);
moveUpperThumb();
}
}
#Override
public boolean shouldScroll(int direction) {
return false;
}
/** Moves the location of the upper thumb, and sets its corresponding value in the slider.*/
public void moveUpperThumb() {
int thumbMiddle = 0;
switch (slider.getOrientation()) {
case JSlider.HORIZONTAL:
int halfThumbWidth = thumbRect.width / 2;
int thumbLeft = currentMouseX - offset;
int trackLeft = trackRect.x;
int trackRight = trackRect.x + (trackRect.width - 1);
int hMax = xPositionForValue(slider.getMaximum() -
slider.getExtent());
if (drawInverted()) {
trackLeft = hMax;
}
else {
trackRight = hMax;
}
thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth);
thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth);
setThumbLocation(thumbLeft, thumbRect.y);//setThumbLocation
thumbMiddle = thumbLeft + halfThumbWidth;
slider.setValue(valueForXPosition(thumbMiddle));
break;
default:
return;
}
}
}
}