I'm new to programming graphic applications in java and I'm having some trouble with this one in particular, what it should do is that it should create two rectangles moving right to left. my issue is that for some reason the program does move the rectangles but doesn't show the rectangles and when it does they are for some unknown reason glitched with only two sides visible. here's the code:
Rectangle's class:
import javax.swing.JComponent;
import java.awt.Rectangle;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class TubeComponent extends JComponent
{
private final static int WIDTH = 20;
private Rectangle up, down;
private int windowLength;
private int windowWidth;
public TubeComponent(int aWidth, int aHeight)
{
windowLength = aWidth;
windowWidth = aHeight;
up = new Rectangle();
down = new Rectangle();
up.setLocation(windowWidth, 0);
int newHeight = (int)((windowLength - WIDTH) * Math.random());
up.setSize(WIDTH, newHeight);
down.setSize(WIDTH, windowLength - newHeight - WIDTH);
down.setLocation(windowWidth, (int) (up.getHeight() + WIDTH));
}
public void randomize()
{
up.setLocation(windowWidth, 0);
int newHeight = (int)((windowLength - WIDTH) * Math.random());
up.setSize(WIDTH, newHeight);
down.setSize(WIDTH, windowLength - newHeight - WIDTH);
down.setLocation(windowWidth, (int) (up.getHeight() + WIDTH));
repaint();
}
#Override
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.draw(up);
g2.draw(down);
System.out.println("ascissa " + getX() + " ordinata " + getY() + " altezza " + getHeight() + " larghezza " + getWidth());
}
public void moveBy(int dx, int dy)
{
up.translate(dx, dy);
down.translate(dx, dy);
repaint();
}
public int getX()
{
return (int) up.getX();
}
public int getY()
{
return (int) up.getY();
}
public int getHeight()
{
return (int) up.getHeight();
}
public int getWidth()
{
return (int) up.getWidth();
}
}
Frame class:
import javax.swing.JFrame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Scene extends JFrame{
private final static int HEIGHT = 400;
private final static int WIDTH = 500;
private final static int SPEED = 4;
private final static int PING = 1;
private TubeComponent tube;
public Scene()
{
tube = new TubeComponent(WIDTH, HEIGHT);
add(tube);
setSize(HEIGHT, WIDTH);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("flappy");
ActionListener a = new TimeListener();
Timer t = new Timer(PING, a);
t.start();
}
private class TimeListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e) {
tube.moveBy(-1, 0);
if(tube.getX() < -1*tube.getWidth())
{
tube.randomize();
}
System.out.println("ascissa " + tube.getX() + " ordinata " + tube.getY() + " altezza " + tube.getHeight() + " larghezza " + tube.getWidth());
}
}
}
Executable class:
import javax.swing.JFrame;
public class FrameViewer {
public static void main(String[] args)
{
Scene s = new Scene();
}
}
I've left the print command to show that the rectangle is actually there and isn't out of bounds. I've tried simplifying the class (by making it print a still rectangle to see if it was my computer but even though it still didn't work, by programming another project with just a still rectangle and that works.
Related
I'm having issues drawing some circles to my JFrame. I originally had it using the default layout and realized this was only adding the most recent circle, so I changed the layout to null, and now nothing gets drawn. I've also tried frame.setLayout(new FlowLayout()) which also doesn't draw anything. Any help would be appreciated!
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
/**
* #author Christopher Nielson
*
*/
public class Main {
private static JFrame frame;
private static Random rand;
private static Jiggler jiggler;
private static ArrayList<JComponent> circles;
private static int fps;
public static void main(String[] args) {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.setBounds(100, 100, 450, 450);
rand = new Random();
circles = new ArrayList<JComponent>();
int x = frame.getWidth();
int y = frame.getHeight();
for (int i = 0; i < Integer.parseInt(args[0]); i++) {
circles.add(new Circle(rand.nextInt(frame.getWidth()), rand.nextInt(frame.getHeight()),
rand.nextInt(frame.getWidth() / 10) + 100, rand.nextInt(frame.getHeight() / 10) + 100, null));
}
circles.forEach(current -> {
frame.add(current);
});
frame.setVisible(true);
jiggler = new Jiggler(circles, new JLabel("FPS: ")); // TODO add fps
jiggler.run();
}
}
And this is one reason you'll see us recommending time and time again to avoid using null layouts like the plague.
Having said that, your main problem is a design problem, not a layout problem, and that problem being that your Circle class shouldn't extend JComponent or any component for that matter, since if you want to draw multiple circles, you should have only one component, probably a JPanel doing the drawing, and the Circles should be logical classes, classes that have a public void draw(Graphics g) method, not component classes. You would pass the List of Circles to your drawing JPanel, and it would draw the Circles in its paintComponent method by calling the draw(g) methods of each Circle in the list.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawChit extends JPanel {
private static final int PREF_W = 900;
private static final int PREF_H = 700;
private static final int MAX_SHAPES = 30;
private List<MyShape> shapes = new ArrayList<>();
public DrawChit() {
setBackground(Color.WHITE);
for (int i = 0; i < MAX_SHAPES; i++) {
double x = (PREF_W - 100) * Math.random();
double y = (PREF_H - 100) * Math.random();
double w = 100 + (Math.random() * PREF_W) / 10;
double h = 100 + (Math.random() * PREF_H) / 10;
Ellipse2D ellipse = new Ellipse2D.Double(x, y, w, h);
float hue = (float) Math.random();
double delta = 0.3;
float saturation = (float) (Math.random() * delta + (1 - delta));
float brightness = (float) (Math.random() * delta + (1 - delta));
Color color = Color.getHSBColor(hue, saturation, brightness);
shapes.add(new MyShape(ellipse, color));
}
// we'll throw a black square in the middle!
int rectW = 200;
int rectX = (PREF_W - rectW) / 2;
int rectY = (PREF_H - rectW) / 2;
shapes.add(new MyShape(new Rectangle(rectX, rectY, rectW, rectW), Color.BLACK));
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// use anti-aliasing to make graphics smooth
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// iterate through the shapes list, filling all
for (MyShape shape : shapes) {
shape.fill(g2);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouse extends MouseAdapter {
private Point p0 = null;
private MyShape shape = null;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
// iterate *backwards* so get top-most Shape
for (int i = shapes.size() - 1; i >= 0; i--) {
if (shapes.get(i).contains(e.getPoint())) {
p0 = e.getPoint();
shape = shapes.get(i);
// move selected shape to the top!
shapes.remove(shape);
shapes.add(shape);
repaint();
return;
}
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (p0 != null) {
moveShape(e.getPoint());
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (p0 != null) {
moveShape(e.getPoint());
p0 = null;
shape = null;
}
}
// translates the shape
private void moveShape(Point p1) {
int deltaX = p1.x - p0.x;
int deltaY = p1.y - p0.y;
shape.translate(deltaX, deltaY);
p0 = p1;
repaint();
}
}
private static void createAndShowGui() {
DrawChit mainPanel = new DrawChit();
JFrame frame = new JFrame("Draw Chit");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class MyShape {
private Path2D path = new Path2D.Double();
private Color color;
public MyShape(Shape shape, Color color) {
path.append(shape, true);
this.color = color;
}
public boolean contains(Point p) {
return path.contains(p);
}
public void draw(Graphics2D g2) {
g2.setColor(color);
g2.draw(path);
}
public void fill(Graphics2D g2) {
g2.setColor(color);
g2.fill(path);
}
public void translate(int deltaX, int deltaY) {
path.transform(AffineTransform.getTranslateInstance(deltaX, deltaY));
}
}
I'm very confused as to why my scoreboard isn't updating on screen. The scores are increasing (I checked with debugger, also the ball is being centered). But the scoreboard isn't updating at all it constantly says "0 : 0"
Pong Class
package com.dheraxysgames.pong;
import java.awt.Dimension;
import javax.swing.JFrame;
public class Pong extends JFrame{
private static final long serialVersionUID = 1L;
//Set Resolution
public static final int width = 300,
height = width / 4 * 3,
scale = 3;
public Pong() {
Dimension size = new Dimension(width * scale, height * scale);
setSize(size);
setTitle("PONG");
setResizable(false);
setVisible(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new GamePanel());
}
public static int getWindowWidth(){
return width * scale;
}
public static int getWindowHeight(){
return height * scale;
}
public static void main(String[] args) {
new Pong();
}
}
GamePanel Class
package com.dheraxysgames.pong;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class GamePanel extends JPanel implements ActionListener, KeyListener {
private static final long serialVersionUID = 1L;
Ball ball = new Ball();
Player player = new Player();
AI ai = new AI(this);
public GamePanel(){
Timer time = new Timer(50, this);
time.start();
this.addKeyListener(this);
this.setFocusable(true);
}
private void update(){
player.update();
ai.update();
ball.update();
ball.checkCollision(player);
ball.checkCollision(ai);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, Pong.getWindowWidth(), Pong.getWindowHeight());
g.setColor(Color.WHITE);
Font font = new Font("IMMORTAL", Font.BOLD, 50);
g.setFont(font);
g.drawString(player.score + " : " + ai.score, Pong.getWindowWidth() / 2 - 60, 50);
player.paint(g);
ai.paint(g);
ball.paint(g);
}
public Ball getBall(){
return ball;
}
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
//Keyboard
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) player.setYVelocity(-10);
if (e.getKeyCode() == KeyEvent.VK_DOWN) player.setYVelocity(10);
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) player.setYVelocity(0);
if (e.getKeyCode() == KeyEvent.VK_DOWN) player.setYVelocity(0);
}
public void keyTyped(KeyEvent e) {
}
}
Player Class
package com.dheraxysgames.pong;
import java.awt.Color;
import java.awt.Graphics;
public class Player {
public int score = 0;
private static int width = 50,
height = 150;
private int x = 800, y = (Pong.getWindowHeight() / 2) - (height / 2),
yV = 0;
public Player() {
}
public void update(){
y += yV;
}
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(x, y, width, height);
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getWidth(){
return width;
}
public int getHeight(){
return height;
}
public void setYVelocity(int speed){
yV = speed;
}
}
AI Class
package com.dheraxysgames.pong;
import java.awt.Color;
import java.awt.Graphics;
public class AI {
public int score = 0;
private static int width = 50,
height = 150;
private GamePanel field;
private int x = 50, y = (Pong.getWindowHeight() / 2) - (height / 2),
yV = 0;
public AI(GamePanel game) {
this.field = game;
}
public AI(){
}
public void update(){
if(field.getBall().getY() < this.y) yV = -8;
if(field.getBall().getY() > this.y) yV = 8;
y += yV;
}
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(x, y, width, height);
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getWidth(){
return width;
}
public int getHeight(){
return height;
}
public void setYVelocity(int speed){
yV = speed;
}
}
Ball Class
package com.dheraxysgames.pong;
import java.awt.Color;
import java.awt.Graphics;
public class Ball {
private int x = Pong.getWindowWidth() / 2, y = Pong.getWindowHeight() / 2,
xV = 10, yV = 10;
private static int size = 40;
Player player = new Player();
AI ai = new AI();
public void update() {
x += xV;
y += yV;
if (x < 0){
reverseXDirection();
player.score++;
x = Pong.getWindowWidth() / 2;
y = Pong.getWindowHeight() / 2;
}
if (x > Pong.getWindowWidth() - size){
reverseXDirection();
ai.score++;
x = Pong.getWindowWidth() / 2;
y = Pong.getWindowHeight() / 2;
}
if (y < 0 || y > Pong.getWindowHeight() - size - 38) reverseYDirection();
}
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillOval(x, y, size, size);
}
private void reverseXDirection(){
xV = -xV;
}
private void reverseYDirection(){
yV = -yV;
}
public void checkCollision(Player p) {
if (this.x + size > p.getX() && this.x + size < p.getX() + p.getWidth()){
if (this.y + size > p.getY() && this.y + size < p.getY() + p.getHeight()){
reverseXDirection();
}
}
}
public void checkCollision(AI ai) {
if (this.x > ai.getX() && this.x < ai.getX() + ai.getWidth()){
if (this.y > ai.getY() && this.y < ai.getY() + ai.getHeight()){
reverseXDirection();
}
}
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}
In you're Ball class the score you're updating is not the same score that is being checked in the GamePanel class.
Notice how in both classes you are calling
Player player = new Player();
AI ai = new AI();
player and ai in Ball are seperate instances from the player and ai in GamePanel.
You will need to get the player and ai from the GamePanel class and pass them to the Ball class. The easiest way to do this would probably be to give Ball a constructor like so
Player player;
AI ai;
public Ball(Player player, AI ai) {
this.player = player;
this.ai = ai;
}
And in your GamePanel class change:
Ball ball = new Ball();
Player player = new Player();
AI ai = new AI(this);
To this:
Player player = new Player();
AI ai = new AI(this);
Ball ball = new Ball(player, ai);
It's been a while since I've used java so I'm probably forgetting a simpler way to do this, but this should solve the problem.
I'm having a problem with the paintComponent() method of my JButton. I want to program my own Minesweeper game and when I try to repaint my Tiles(which extend JButton) they don't seem to update. Here is my Tile class:
package mineSweeper;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
public class Tile extends JButton{
/**
*
*/
private static final long serialVersionUID = 5476927382697663397L;
public static final int UNPRESSED = 0;
public static final int PRESSED = 1;
public static final int FLAG = 2;
public static final int BOMB = 3;
public static final int XBOMB = 4;
public static final int HEIGHT = 16;
public static final int WIDTH = 16;
private int paintMode = UNPRESSED;
public Tile(int x, int y){
super();
setBounds(x*WIDTH, y*HEIGHT, WIDTH, HEIGHT);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setMargin(new Insets(0, 0, 0, 0));
setBorder(BorderFactory.createEmptyBorder());
addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
setEnabled(false);
setPaintMode(PRESSED);
repaint();
}
});
}
public void reset(){
setEnabled(true);
setPaintMode(UNPRESSED);
repaint();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
if (getPaintMode()==UNPRESSED)
{
setBackground(Color.LIGHT_GRAY);
g.setColor(Color.WHITE);
g.drawLine(0, 0, WIDTH-1, 0);
g.drawLine(0, 1, WIDTH-2, 1);
g.drawLine(0, 0, 0, HEIGHT-1);
g.drawLine(1, 0, 1, HEIGHT-2);
g.setColor(Color.GRAY);
g.drawLine(WIDTH, HEIGHT, 1, HEIGHT);
g.drawLine(WIDTH, HEIGHT-1, 2, HEIGHT-1);
g.drawLine(WIDTH, HEIGHT, WIDTH, 1);
g.drawLine(WIDTH-1, HEIGHT, WIDTH-1, 2);
}
if (getPaintMode()==PRESSED)
{
setBackground(Color.LIGHT_GRAY);
g.drawLine(0, 0, WIDTH, 0);
g.drawLine(0, 0, 0, HEIGHT);
}
g.dispose();
}
public int getPaintMode() {
return paintMode;
}
public void setPaintMode(int mode) {
mode = paintMode;
}
}
and the class Board
package mineSweeper;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Board extends JFrame{
/**
*
*/
private static final long serialVersionUID = 2769769568511334271L;
public static Tile[][] tile;
public JPanel panel = new JPanel(null);
public JButton resetButton = new ResetButton("Click here to Reset");
String input;
private static int screenWidth = 400;
private static int screenHeight = 400;
private static final int MAXROWS = 60;
private static final int MAXCOLUMS = 60;
private static final int MINROWS = 2;
private static final int MINCOLUMS = 6;
private static final int RESETBUTTONSIZE = 40;
public Board(){
super("MineSweeper");
askForInputs();
resetButton.setBounds(0, screenHeight, screenWidth, RESETBUTTONSIZE);
tile = new Tile[getColums()][getRows()];
pack();
setSize(screenWidth + getInsets().left + getInsets().right, screenHeight + getInsets().top + getInsets().bottom + RESETBUTTONSIZE);
getContentPane().add(panel);
panel.add(resetButton);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
for (int x = 0; x < getColums(); x++)
{
for (int y = 0; y < getRows(); y++)
{
tile[x][y] = new Tile(x,y);
panel.add(tile[x][y]);
}
}
setVisible(true);
}
private void askForInputs() {
try{
input = JOptionPane.showInputDialog(null, "Enter number of rows ( Maximum " + MAXROWS + " / Minimum " + MINROWS +")" );
Integer.parseInt(input);
}
catch(Exception ex){input = "";}
if (!(input == null) && !(input.isEmpty()) && !(Integer.parseInt(input) < MINROWS)){
if (Integer.parseInt(input) > MAXROWS)
screenHeight = MAXROWS * Tile.HEIGHT;
}
else input = String.valueOf(MAXROWS/4);
screenHeight = Integer.parseInt(input) * Tile.HEIGHT;
try{
input = JOptionPane.showInputDialog(null, "Enter number of colums ( Maximum " + MAXCOLUMS + " / Minimum " + MINCOLUMS + ")" );
Integer.parseInt(input);
}
catch(Exception ex){input = "";}
if (!(input == null) && !(input.isEmpty()) && !(Integer.parseInt(input) < MINCOLUMS))
{
if (Integer.parseInt(input) > MAXCOLUMS)
screenWidth = MAXCOLUMS * Tile.WIDTH;
}
else input = String.valueOf(MAXCOLUMS/4);
screenWidth = Integer.parseInt(input) * Tile.WIDTH;
}
public static void reset(){
for (int x = 0; x < getColums(); x++)
{
for (int y = 0; y < getRows(); y++)
{
tile[x][y].reset();
}
}
}
public static int getScreenWidth() {
return screenWidth;
}
public static void setScreenWidth(int screenWidth) {
Board.screenWidth = screenWidth;
}
public static int getScreenHeight() {
return screenHeight;
}
public static void setScreenHeight(int screenHeight) {
Board.screenHeight = screenHeight;
}
public static int getColums(){
return getScreenWidth() / Tile.WIDTH;
}
public static int getRows(){
return getScreenHeight() / Tile.HEIGHT;
}
public static void main (String args[]){
new Board();
}
}
Don't mind the unused imports.
So my problem is: when I click a Tile I see I clicked it and I can't click it again but it looks the same like before.
What am I doing wrong please help.
There's a number of things pop out at me, but you're main problem is this...
public class Tile extends JButton {
//...
public void setPaintMode(int mode) {
mode = paintMode;
}
}
You never actually assign the current mode to the paintMode variable, the assignment is backwards.
I'd recommend using JFrame#setExtendedState to set the frame MAXIMIZED_BOTH state over the setSize hack you're currently using, it'll at least reduce the amount of code.
I'd also recommend using a GridLayout or GridBagLayout of a null layout any day.
Have you considered using a JToggleButton, it's basically what you're doing now?
I currently have a JPanel inside a JFrame and i need the view to follow an object, the reason i cant move the world is because the object is orbiting another object and so working out how to move the world would be a little more difficult.
Ok, below is an example on how to do this. Note that a SSCCE doesn't need to be OO, so you probably shouldn't copy + paste this into your current project. I will not explain the steps, because pretty much everything was explained in the link I posted. Still, here are the references for the 2D camera and for the object moving in circular path.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import javax.swing.Timer;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example();
}
});
}
public Example() {
JFrame frame = new JFrame();
frame.setContentPane(new DrawingPanel());
frame.setSize(400, 300);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
}
class DrawingPanel extends JPanel {
int angle = 0;
int rotation = 0;
int radius = 150;
int ovalX = 150;
int ovalY = 150;
int ovalWidth = 100;
int ovalHeight = 100;
int ovalCenterX = ovalX + ovalWidth / 2;
int ovalCenterY = ovalY + ovalHeight / 2;
int recX;
int recY;
int recWidth = 50;
int recHeight = 50;
int recCenterX;
int recCenterY;
int WORLD_SIZE_X = 6000;
int WORLD_SIZE_Y = 6000;
int camX;
int camY;
public DrawingPanel() {
ActionListener al = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
angle++;
rotation++;
recCenterX = (int) ((int) ovalCenterX + Math.sin(Math.toRadians(angle)) * radius);
recCenterY = (int) ((int) ovalCenterY + Math.cos(Math.toRadians(angle)) * radius);
recX = recCenterX - recWidth / 2;
recY = recCenterY - recHeight / 2;
repaint();
}
};
Timer timer = new Timer(15, al);
timer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D gg = (Graphics2D) g;
gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int VIEWPORT_SIZE_X = getWidth();
int VIEWPORT_SIZE_Y = getHeight();
int offsetMaxX = WORLD_SIZE_X - VIEWPORT_SIZE_X;
int offsetMaxY = WORLD_SIZE_Y - VIEWPORT_SIZE_Y;
camX = recCenterX - VIEWPORT_SIZE_X / 2;
camY = recCenterY - VIEWPORT_SIZE_Y / 2;
if (camX > offsetMaxX) {
camX = offsetMaxX;
}
if (camY > offsetMaxY) {
camY = offsetMaxY;
}
gg.translate(-camX, -camY);
gg.setColor(Color.BLUE);
gg.fillOval(ovalX, ovalY, ovalWidth, ovalHeight);
AffineTransform old = gg.getTransform();
gg.rotate(Math.toRadians(rotation), recCenterX, recCenterY);
gg.setColor(Color.RED);
gg.drawRect(recX, recY, recWidth, recHeight);
gg.setTransform(old);
gg.setColor(Color.GREEN);
gg.drawLine(ovalCenterX, ovalCenterY, recCenterX, recCenterY);
}
}
}
I'm trying to fire a projectile in the mouse direction but i am having trouble.
The angles are wrong, and by that I mean it will only go up left or in the top-left corner.
This is my Gun class for which I fire the Bullet.
package assets;
import Reaper.Game;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
public class Gun
{
public ArrayList<Bullet> bullets;
protected double angle;
Mouse mouse = new Mouse();
private BufferedImage image;
private int centerX = Game.WIDTH / 2;
private int centerY = Game.HEIGHT;
public Gun()
{
bullets = new ArrayList<Bullet>();
image = null;
try
{
image = ImageIO.read(new File("assets/gun.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
public BufferedImage loadImage()
{
return image;
}
public int getImageWidth()
{
return image.getWidth(null);
}
public int getImageHeight()
{
return image.getHeight(null);
}
public void rotate(Graphics g)
{
angle = Math.atan2(centerY - mouse.getMouseY(), centerX - mouse.getMouseX()) - Math.PI / 2;
((Graphics2D) g).rotate(angle, centerX, centerY);
g.drawImage(image, Game.WIDTH / 2 - image.getWidth() / 2,
900 - image.getHeight(), image.getWidth(), image.getHeight(),
null);
}
public Image getImage()
{
return image;
}
public void update()
{
shoot();
for (int i = 0; i < bullets.size(); i++)
{
Bullet b = bullets.get(i);
b.update();
}
}
public void shoot()
{
if (mouse.mouseB == 1)
{
double dx = mouse.getMouseX() - Game.WIDTH / 2;
double dy = mouse.getMouseY() - Game.HEIGHT / 2;
double dir = Math.atan2(dy, dx);
bullets.add(new Bullet(Game.WIDTH / 2, Game.HEIGHT / 2, dir));
mouse.mouseB = -1;
}
}
public void render(Graphics g)
{
for (int i = 0; i < bullets.size(); i++)
{
bullets.get(i).render(g);
}
rotate(g);
}
}
This is my Bullet class:
package assets;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Bullet
{
private double dx, dy;
private int x, y;
private double dir;
private BufferedImage image;
public Bullet(int x, int y, double angle)
{
this.x = x;
this.y = y;
this.dir = angle;
image = null;
try
{
image = ImageIO.read(new File("assets/bolt.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
dx = Math.cos(dir);
dy = Math.sin(dir);
}
public void update()
{
x += dx;
y += dy;
System.out.println("dx : " + dx + " " + dy);
}
public void render(Graphics g)
{
g.drawImage(image, x, y, image.getWidth(), image.getHeight(), null);
}
public BufferedImage getImage()
{
return image;
}
}
And this is the main Game class:
package Reaper;
import Reaper.graphics.Screen;
import assets.Gun;
import assets.Mouse;
import gameState.MenuState;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferStrategy;
public class Game extends Canvas implements Runnable
{
private static final long serialVersionUID = 1L;
public static int WIDTH = 900;
public static int HEIGHT = 900;
public static int scale = 3;
public int frames = 0;
public int updates = 0;
private boolean running = false;
private Thread thread;
private JFrame frame;
#SuppressWarnings("unused")
private Screen screen;
private Gun gun;
private MenuState mns;
private Mouse mouse;
public Game()
{
Dimension size = new Dimension(WIDTH, HEIGHT);
setPreferredSize(size);
screen = new Screen(WIDTH, HEIGHT);
frame = new JFrame();
gun = new Gun();
mns = new MenuState();
mouse = new Mouse();
addMouseListener(mouse);
addMouseMotionListener(mouse);
}
public static void main(String[] args)
{
Game game = new Game();
game.frame.setResizable(false);
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setVisible(true);
game.frame.setLocationRelativeTo(null);
game.strat();
}
public void strat()
{
running = true;
thread = new Thread(this, "Reaper");
thread.start();
}
public void stop()
{
running = false;
try
{
thread.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public void run()
{
long timer = System.currentTimeMillis();
long lastTime = System.nanoTime();
double ns = 1000000000.0 / 60;
double delta = 0;
while (running)
{
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1)
{
update();
updates++;
delta--;
}
render();
frames++;
if (System.currentTimeMillis() - timer > 1000)
{
timer = System.currentTimeMillis();
frame.setTitle("Reaper! " + " | " + updates + " ups , " + frames + " fps");
updates = 0;
frames = 0;
}
}
stop();
}
public void update()
{
if (mns.play)
{
gun.update();
}
}
public void render()
{
BufferStrategy bs = getBufferStrategy();
if (bs == null)
{
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.fillRect(0, 0, WIDTH, HEIGHT);
if (mns.menu)
{
mns.draw(g);
}
if (mns.play)
{
g.clearRect(0, 0, WIDTH, HEIGHT);
g.drawImage(mns.getImage(), 0, 0, mns.getImageWidth(), mns.getImageHeight(), this);
gun.render(g);
}
if (mns.rules)
{
g.clearRect(0, 0, WIDTH, HEIGHT);
}
bs.show();
}
}
I know it's very badly coded, and I will try to fix it as much as I can, but I am really stuck on this. Searched around the web, tried some of the solutions but it wont work. I guess I'm doing it wrong by putting methods in wrong places and calling them, I guess.
I know it's very badly coded, and I will try to fix it as much as I can, ...
Next time, consider first cleaning up the mess and then asking the question.
(Are the variables storing the values returned by getMouseX() and getMouseY() really static?)
However, the main reason for the actual problem are the x and y values in the Bullet class:
class Bullet
{
private double dx, dy;
private int x, y;
....
public void update()
{
x += dx;
y += dy;
System.out.println("dx : " + dx + " " + dy);
}
...
}
They are declared as int values. Imagine what happens in the update method, for example, when x=0 and dx = 0.75: It will compute 0+0.75 = 0.75, truncate this to be an int value, and the result will be 0.
Thus, the x and y values will never change, unless the dx and dy values are >= 1.0, respectively.
Just changing the type of x and y to double will solve this. You'll have to add casts in the render method accordingly:
g.drawImage(image, (int)x, (int)y, ...);
But you should really clean this up.