Just a small program I quickly made to see if I could perform collisions with a rectangle object and a rotating rectangle object.
Problem arises when rotating rectangle object, the collision box doesn't rotate, only the image rotates.
In this code I tried to use shape object but and performed transformations to it, but was unsuccessful.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.util.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
public class test extends JFrame implements Runnable,KeyListener
{
MyDrawPanel playPanel = new MyDrawPanel();
Thread th= new Thread(this);
int w=500, h=539;
Rectangle s1;
Rectangle r1;
int x=50,y=50;
int spx=0;
int spy=0;
int b=0;
int spin=0,spin2=0;
Shape p1;
AffineTransform tx,ax;
public static void main (String [] args)
{
new test();
}
public test()
{
s1= new Rectangle(200,200,106,16);
p1= new Rectangle(200,200,106,16);
r1= new Rectangle(x,y,50,50);
this.setSize(w,h);
this.setVisible(true);
this.setResizable(true);
this.addKeyListener(this);
this.add(playPanel);
playPanel.setDoubleBuffered(true);
th.start();
}
public void keyPressed(KeyEvent e)
{
int key =e.getKeyCode();
if (key == KeyEvent.VK_DOWN)
{
spy=2;
}
if (key == KeyEvent.VK_UP)
{
spy=-2;
}
if (key == KeyEvent.VK_RIGHT)
{
spx=2;
}
if (key == KeyEvent.VK_LEFT)
{
spx=-2;
}
}
public void keyReleased(KeyEvent e)
{
spx=0;
spy=0;
}
public void keyTyped(KeyEvent e)
{}
public void coll()
{
if (r1.getBounds().intersects(p1.getBounds()))
{
b=1;
}
else{b=0;}
}
public void rot()
{
AffineTransform px= new AffineTransform();
px.rotate(Math.toRadians(spin),w/2,h/2);
p1=px.createTransformedShape(s1);
}
///DO TOP HEAD INTERSECT CHECKINGGGGGGGGGGGGGGGGG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
public void run ()
{
while (true)
{
rot();
r1.x+=spx;
r1.y+=spy;
spin+=2;
coll();
repaint();
try
{
Thread.sleep (30);
}
catch (InterruptedException ex)
{
}
}
}
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (b==1)
{
g2.setColor(Color.RED);
}
AffineTransform old= g2.getTransform();
//g2.rotate(Math.toRadians(spin),
//p1.getBounds().x+8,p1.getBounds().y+8);
g2.fillRect(p1.getBounds().x,p1.getBounds().y,106,16);
g2.setTransform(old);
g2.fillRect(r1.x,r1.y,r1.width,r1.height);
}
}
}
//15.31
/* ADD YOUR CODE HERE */
Used Bresenham's algorithm to find all pixels on a Line2D to detect collision between Rectangle and Line through class LineIterator.
Try like below said source, by increased value of spx and spy with difference value of 4 for moving the square faster:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.Iterator;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class RotateRectangleRound extends JFrame implements KeyListener {
private static final long serialVersionUID = 9085168127541601308L;
private Rectangle stableRect;
private int cw = 400, ch = 400;
private boolean collision;
private int spx = 0, spy = 0;
private double radius = 120;
private double angleX = 0, angleY = 0;
private int rotatingVal = 0;
private Line2D line;
private LineIterator iterator;
private Point currentPoint;
private Point2D tp;
private static BasicStroke spinningStroke = new BasicStroke(8);
private static BasicStroke basicStroke = new BasicStroke(1);
private MyPanel panel;
private static boolean startWorker;
private SwingWorker<Void, Void> swingWorker;
public RotateRectangleRound() {
init();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new RotateRectangleRound();
}
});
}
private void init() {
this.setTitle("Rotate Rectangle - Paused");
this.getContentPane().setLayout(new GridLayout(1, 1));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(400, 200, 400, 400);
this.setLayout(new GridLayout(1, 1));
this.addKeyListener(this);
this.setVisible(true);
// getting the window width & height insets explicitly
cw = this.getContentPane().getWidth();
ch = this.getContentPane().getHeight();
// setting the stableRect and movableRect to between of screen except insets
stableRect = new Rectangle(20, 20, 40, 40);
angleX = 192;
angleY = 300;
this.panel = new MyPanel();
this.add(panel);
}
#Override
public void keyTyped(KeyEvent evt) {}
public void keyPressed(KeyEvent evt) {
int key = evt.getKeyCode();
if (key == KeyEvent.VK_DOWN) {
spy = 4;
moveStableRectangle();
} else if (key == KeyEvent.VK_UP) {
spy = -4;
moveStableRectangle();
} else if (key == KeyEvent.VK_RIGHT) {
spx = 4;
moveStableRectangle();
} else if (key == KeyEvent.VK_LEFT) {
spx = -4;
moveStableRectangle();
}
if (key == KeyEvent.VK_SPACE) {
startWorker = (!startWorker);
if (startWorker) {
this.setTitle("Rotate Rectangle");
collision = false;
startRotatingFromPoint();
}else {
this.setTitle("Rotate Rectangle - Paused");
}
}
}
private void moveStableRectangle() {
stableRect.x += spx;
stableRect.y += spy;
repaint();
}
public void keyReleased(KeyEvent evt) {
spx = 0;
spy = 0;
}
private void startRotatingFromPoint() {
swingWorker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
while (startWorker) {
try {
if (rotatingVal == 360)
rotatingVal = 0;
// first getting the angle x, y value for radius 100,
// second adding the half of width & height to rotate
// between screen accordingly with that w & h value
angleX = (Math.sin(Math.toRadians((double) rotatingVal)) * radius) + (cw / 2);
angleY = (Math.cos(Math.toRadians((double) rotatingVal++)) * radius) + (ch / 2);
// calculating collision
collision();
// requesting frame repainting
repaint();
Thread.sleep(10);
} catch (InterruptedException iex) {
iex.printStackTrace();
}
}
return null;
}
};
swingWorker.execute();
}
public void collision() {
if (detectCollision()) {
collision = true;
startWorker = false;
this.setTitle("Rotate Rectangle - Hitted");
} else {
collision = false;
}
}
private boolean detectCollision() {
boolean flag = false;
if(angleX < (cw/2))
line = new Line2D.Double(angleX, angleY, cw / 2, ch / 2);
else
line = new Line2D.Double(cw / 2, ch / 2, angleX, angleY);
//creating a iterator by use of Bresenham's algorithm
iterator = new LineIterator(line);
looperFor:
for (Iterator<Point2D> it = iterator; it.hasNext();) {
//getting Point2D Object of Point Iterator
tp = it.next();
currentPoint = new Point((int) tp.getX(), (int) tp.getY());
if (stableRect.contains(currentPoint)) {
flag = true;
break looperFor;
}
}
//returning the detected collision flag true or false
return flag;
}
class MyPanel extends JPanel {
private static final long serialVersionUID = 1L;
#Override
public void paintComponent(Graphics gr) {
Graphics2D g = (Graphics2D) gr;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setStroke(basicStroke);
if (collision)
g.setColor(Color.RED);
g.fillRect(stableRect.x, stableRect.y, stableRect.width, stableRect.height);
g.setStroke(spinningStroke);
g.drawLine(cw / 2, ch / 2, (int) angleX, (int) angleY);
}
}
}
Hope this would help you.
Related
So I'm trying to awnser this question for like 2-3 hours now, but I can't quite find an fix or resolution for my problem. Like there are no Video tutorials. And because I am new to programming, especially with Java, I just don't know, how to rewrite code, that it matches my code and perfectly works. Here is what I have right now:
Also my project is all based on 2D and you only see your player for right above. So I dont really need Animation for the Player and Entity models, just in case you wondered.
Class: GamePanel
package main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
import entity.Player;
public class GamePanel extends JPanel implements Runnable{
// SCREEN SETTINGS
final int originalTitleSize = 16; // 16x16 title
final int scale = 3; //16x3(scale) = 48
public final int tileSize = originalTitleSize * scale; //48x48 title
final int maxScreenCol = 16;
final int maxScreenRow = 12;
final int screenWidth = tileSize * maxScreenCol; // 768 pixels
final int screenHeight = tileSize * maxScreenRow; // 576 pixels
//FPS
int FPS = 60;
KeyHandler keyH = new KeyHandler();
Thread gameThread;
Player player = new Player(this,keyH);
// Set player's default position
int playerX = 100;
int playerY = 100;
int playerSpeed = 4;
public GamePanel() {
this.setPreferredSize(new Dimension(screenWidth, screenHeight));
this.setBackground(Color.BLACK);
this.setDoubleBuffered(true);
this.addKeyListener(keyH);
this.setFocusable(true);
}
public void startGameThread() {
gameThread = new Thread(this);
gameThread.start();
}
#Override
// public void run() {
//
// double drawInterval = 1000000000/FPS; // 0.0166666... seconds
// double nextDrawTime = System.nanoTime() + drawInterval;
//
//
//
// while(gameThread != null) {
//
// // System.out.println("The game loop is running");
//
// // 1 UPDATE: update information such as character positions
// update();
//
//
//
// // 2 DRAW: draw the screen with the updated information
// repaint();
//
// try {
// double remainingTime = nextDrawTime - System.nanoTime();
// remainingTime = remainingTime/1000000;
//
// if(remainingTime < 0) {
// remainingTime = 0;
// }
//
// Thread.sleep((long) remainingTime);
//
// nextDrawTime += drawInterval;
//
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }
public void run() {
double drawInterval = 1000000000/FPS;
double delta = 0;
long lastTime = System.nanoTime();
long currentTime;
long timer = 0;
int drawCount = 0;
while(gameThread != null) {
currentTime =System.nanoTime();
delta += (currentTime - lastTime) / drawInterval;
timer += (currentTime -lastTime);
lastTime = currentTime;
if(delta >=1) {
update();
repaint();
delta--;
drawCount++;
}
if(timer >= 1000000000) {
System.out.println("FPS:" + drawCount);
drawCount = 0;
timer = 0;
}
}
}
public void update() {
player.update();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
player.draw(g2);
g2.dispose();
}
}
Class: KeyHandler
package main;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class KeyHandler implements KeyListener{
public boolean upPressed, downPressed, leftPressed, rightPressed;
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if(code == KeyEvent.VK_W) {
upPressed = true;
}
if(code == KeyEvent.VK_S) {
downPressed = true;
}
if(code == KeyEvent.VK_A) {
leftPressed = true;
}
if(code == KeyEvent.VK_D) {
rightPressed = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
if(code == KeyEvent.VK_W) {
upPressed = false;
}
if(code == KeyEvent.VK_S) {
downPressed = false;
}
if(code == KeyEvent.VK_A) {
leftPressed = false;
}
if(code == KeyEvent.VK_D) {
rightPressed = false;
}
}
}
Class: Main
package main;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setResizable(false);
window.setTitle("Zombio 0.0.0.01");
GamePanel gamePanel = new GamePanel();
window.add(gamePanel);
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
gamePanel.startGameThread();
}
}
I also have an Player:
package entity;
import java.awt.Color;
import java.awt.Graphics2D;
import main.GamePanel;
import main.KeyHandler;
public class Player extends Entity{
GamePanel gp;
KeyHandler keyH;
public Player(GamePanel gp, KeyHandler keyH) {
this.gp = gp;
this.keyH = keyH;
setDefaultValues();
}
public void setDefaultValues() {
x = 100;
y = 100;
speed = 4;
}
public void update() {
if(keyH.upPressed == true) {
y -= speed;
}
else if(keyH.downPressed == true) {
y += speed;
}
else if(keyH.leftPressed == true) {
x -= speed;
}
else if(keyH.rightPressed == true) {
x += speed;
}
}
public void draw(Graphics2D g2) {
g2.setColor(Color.yellow);
g2.fillRect(x, y, gp.tileSize, gp.tileSize); //(x, y, width, height)
}
}
And this Player is based on the normal-entity:
package entity;
public class Entity {
public int x, y;
public int speed;
}
I know, this is a lot you need to look through, but I really don't know, what exaclty you need. I would like to implement the rotation in the Player Class, if this is possible for you. Also please not only write Code and set it as awnser, I really have no expirience, so take my by the hand :)
Thanks for your help, appreciate it!
You will want to have a look at:
Key bindings - these will solve all the focus related issues with KeyListener
Concurrency in Swing and probably switch over to using a Swing Timer. Swing is NOT thread safe, it's not a good idea to use Thread as your "main loop".
So your basic problem is a "simple" trigonometry problem (I as say simple, but I'm an idiot). You have two points in space and need to calculate the angle between them, for example...
// Radians
-Math.atan2(startY - endY, startX - endX)
Runnable example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
GamePanel gamePanel = new GamePanel();
JFrame frame = new JFrame();
frame.add(gamePanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
gamePanel.startGameThread();
}
});
}
public class GamePanel extends JPanel { //implements Runnable {
// SCREEN SETTINGS
final int originalTitleSize = 16; // 16x16 title
final int scale = 3; //16x3(scale) = 48
public final int tileSize = originalTitleSize * scale; //48x48 title
final int maxScreenCol = 16;
final int maxScreenRow = 12;
final int screenWidth = tileSize * maxScreenCol; // 768 pixels
final int screenHeight = tileSize * maxScreenRow; // 576 pixels
//FPS
int FPS = 60;
Player player = new Player(this);
private Timer timer;
private Set<KeyAction.Direction> movementState = new HashSet<>();
private Point lastKnownMousePoint;
public GamePanel() {
this.setBackground(Color.BLACK);
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
lastKnownMousePoint = e.getPoint();
}
});
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "Pressed.up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "Released.up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "Pressed.down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), "Released.down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "Pressed.left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "Released.left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "Pressed.right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "Released.right");
ActionMap am = getActionMap();
am.put("Pressed.up", new KeyAction(KeyAction.Direction.UP, true, movementState));
am.put("Released.up", new KeyAction(KeyAction.Direction.UP, false, movementState));
am.put("Pressed.down", new KeyAction(KeyAction.Direction.DOWN, true, movementState));
am.put("Released.down", new KeyAction(KeyAction.Direction.DOWN, false, movementState));
am.put("Pressed.left", new KeyAction(KeyAction.Direction.LEFT, true, movementState));
am.put("Released.left", new KeyAction(KeyAction.Direction.LEFT, false, movementState));
am.put("Pressed.right", new KeyAction(KeyAction.Direction.RIGHT, true, movementState));
am.put("Released.right", new KeyAction(KeyAction.Direction.RIGHT, false, movementState));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(screenWidth, screenHeight);
}
public void startGameThread() {
if (timer == null) {
timer = new Timer((int) Math.floor(1000f / FPS), new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
});
}
timer.start();
}
public void update() {
if (movementState.contains(KeyAction.Direction.UP)) {
player.y -= player.speed;
} else if (movementState.contains(KeyAction.Direction.DOWN)) {
player.y += player.speed;
} else if (movementState.contains(KeyAction.Direction.LEFT)) {
player.x -= player.speed;
} else if (movementState.contains(KeyAction.Direction.RIGHT)) {
player.x += player.speed;
}
if (lastKnownMousePoint != null) {
// This assumes that character is facing "UP" by default
// That is, 0 has the character entity facing towards to the
// top of the sceen. If the character is facing in a different
// direction, then you will need to offset this calculation
// to compenstate, but that might be better done in the player
// entity
double angle = -Math.toDegrees(Math.atan2(player.x - lastKnownMousePoint.x, player.y - lastKnownMousePoint.y));
player.angleInDegrees = angle;
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
player.draw(g2);
g2.dispose();
}
}
public class KeyAction extends AbstractAction {
enum Direction {
UP, DOWN, LEFT, RIGHT
}
private Direction direction;
private boolean activate;
private Set<Direction> inputState;
public KeyAction(Direction direction, boolean activate, Set<Direction> inputState) {
this.direction = direction;
this.activate = activate;
this.inputState = inputState;
}
#Override
public void actionPerformed(ActionEvent e) {
if (activate) {
inputState.add(direction);
} else {
inputState.remove(direction);
}
}
}
public class Entity {
public int x;
public int y;
public int speed;
}
public class Player extends Entity {
GamePanel gp;
double angleInDegrees = 0;
public Player(GamePanel gp) {
this.gp = gp;
setDefaultValues();
}
public void setDefaultValues() {
x = 100;
y = 100;
speed = 4;
}
public void draw(Graphics2D g2) {
g2 = (Graphics2D) g2.create();
g2.translate(x, y);
g2.rotate(Math.toRadians(angleInDegrees), (gp.tileSize / 2), (gp.tileSize / 2));
g2.setColor(Color.yellow);
g2.fillRect(0, 0, gp.tileSize, gp.tileSize);
g2.setColor(Color.RED);
g2.drawLine((gp.tileSize / 2), (gp.tileSize / 2), (gp.tileSize / 2), 0);
g2.dispose();
}
}
}
Oh, and also the rotation point is not right in the middle of the player (rectangle). Some dont need accurancy, I really do
Just beware, you're probably never going to find the "exact" solutions to your problems and you're going to need to take the time to experiment ;)
Okay, admittedly, that seemed to work for me, until I started debugging it. The problem was, the original code was calculating the angle from the mouse point and the players current x/y point. It should be using the players "rotation" point, which, in this example, is the players mid point.
So, I added...
public Point midPoint() {
return new Point(x + (gp.tileSize / 2), y + (gp.tileSize / 2));
}
to Player, so we can easily get the player's mid point (and not have to retype that a lot)
I then updated the angle calculation to make use of it, for example..
Point playerMidPoint = player.midPoint();
double angle = Math.toDegrees(Math.atan2(lastKnownMousePoint.y - playerMidPoint.y, lastKnownMousePoint.x - playerMidPoint.x)) + 90d;
player.angleInDegrees = angle;
Runnable example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
GamePanel gamePanel = new GamePanel();
JFrame frame = new JFrame();
frame.add(gamePanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
gamePanel.startGameThread();
}
});
}
public class GamePanel extends JPanel { //implements Runnable {
// SCREEN SETTINGS
final int originalTitleSize = 16; // 16x16 title
final int scale = 3; //16x3(scale) = 48
public final int tileSize = originalTitleSize * scale; //48x48 title
final int maxScreenCol = 16;
final int maxScreenRow = 12;
final int screenWidth = tileSize * maxScreenCol; // 768 pixels
final int screenHeight = tileSize * maxScreenRow; // 576 pixels
//FPS
int FPS = 60;
Player player = new Player(this);
private Timer timer;
private Set<KeyAction.Direction> movementState = new HashSet<>();
private Point lastKnownMousePoint;
public GamePanel() {
this.setBackground(Color.BLACK);
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
lastKnownMousePoint = new Point(e.getPoint());
}
});
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "Pressed.up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "Released.up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "Pressed.down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), "Released.down");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "Pressed.left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "Released.left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "Pressed.right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "Released.right");
ActionMap am = getActionMap();
am.put("Pressed.up", new KeyAction(KeyAction.Direction.UP, true, movementState));
am.put("Released.up", new KeyAction(KeyAction.Direction.UP, false, movementState));
am.put("Pressed.down", new KeyAction(KeyAction.Direction.DOWN, true, movementState));
am.put("Released.down", new KeyAction(KeyAction.Direction.DOWN, false, movementState));
am.put("Pressed.left", new KeyAction(KeyAction.Direction.LEFT, true, movementState));
am.put("Released.left", new KeyAction(KeyAction.Direction.LEFT, false, movementState));
am.put("Pressed.right", new KeyAction(KeyAction.Direction.RIGHT, true, movementState));
am.put("Released.right", new KeyAction(KeyAction.Direction.RIGHT, false, movementState));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(screenWidth, screenHeight);
}
public void startGameThread() {
if (timer == null) {
timer = new Timer((int) Math.floor(1000f / FPS), new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
});
}
timer.start();
}
public void update() {
if (movementState.contains(KeyAction.Direction.UP)) {
player.y -= player.speed;
} else if (movementState.contains(KeyAction.Direction.DOWN)) {
player.y += player.speed;
} else if (movementState.contains(KeyAction.Direction.LEFT)) {
player.x -= player.speed;
} else if (movementState.contains(KeyAction.Direction.RIGHT)) {
player.x += player.speed;
}
if (lastKnownMousePoint != null) {
// This assumes that character is facing "UP" by default
// That is, 0 has the character entity facing towards to the
// top of the sceen. If the character is facing in a different
// direction, then you will need to offset this calculation
// to compenstate, but that might be better done in the player
// entity
Point playerMidPoint = player.midPoint();
double angle = Math.toDegrees(Math.atan2(lastKnownMousePoint.y - playerMidPoint.y, lastKnownMousePoint.x - playerMidPoint.x)) + 90d;
player.angleInDegrees = angle;
repaint();
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
player.draw(g2);
g2.dispose();
if (lastKnownMousePoint != null) {
g2 = (Graphics2D) g;
g2.setColor(Color.GREEN);
int midX = player.x + (tileSize / 2);
int midY = player.y + (tileSize / 2);
g2.drawLine(midX, midY, lastKnownMousePoint.x, lastKnownMousePoint.y);
g2.dispose();
}
}
}
public class KeyAction extends AbstractAction {
enum Direction {
UP, DOWN, LEFT, RIGHT
}
private Direction direction;
private boolean activate;
private Set<Direction> inputState;
public KeyAction(Direction direction, boolean activate, Set<Direction> inputState) {
this.direction = direction;
this.activate = activate;
this.inputState = inputState;
}
#Override
public void actionPerformed(ActionEvent e) {
if (activate) {
inputState.add(direction);
} else {
inputState.remove(direction);
}
}
}
public class Entity {
public int x;
public int y;
public int speed;
}
public class Player extends Entity {
GamePanel gp;
double angleInDegrees = 0;
public Player(GamePanel gp) {
this.gp = gp;
setDefaultValues();
}
public void setDefaultValues() {
x = 100;
y = 100;
speed = 4;
}
public Point midPoint() {
return new Point(x + (gp.tileSize / 2), y + (gp.tileSize / 2));
}
public void draw(Graphics2D g2) {
g2 = (Graphics2D) g2.create();
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
at.rotate(Math.toRadians(angleInDegrees), (gp.tileSize / 2d), (gp.tileSize / 2d));
g2.transform(at);
g2.setColor(Color.yellow);
g2.fillRect(0, 0, gp.tileSize, gp.tileSize);
g2.setColor(Color.RED);
g2.drawLine((gp.tileSize / 2), (gp.tileSize / 2), (gp.tileSize / 2), 0);
g2.dispose();
}
}
}
I am trying to "teleport" objects to the opposite positions whenever they get out of screen. I've managed to do this with right & bottom sides, but for some reason, which I haven't figured out, the star objects won't go off screen on TOP & LEFT sides UNLESS the lerping speed is high enough.
Preview:
Main.java
package asteroids;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class Main extends Canvas implements KeyListener {
private boolean gameOver;
private BufferStrategy backBuffer;
private Dimension dimension = new Dimension(Config.WINDOW_WH[0], Config.WINDOW_WH[1]);
private List<Star> stars = new ArrayList<Star>();
private HashMap<Integer,Boolean> keyDownMap = new HashMap<Integer, Boolean>();
private Ship ship;
private Image bg;
private float starGoalX, starGoalY;
public Main() {
// Initialize Window
initWindow();
addKeyListener(this);
this.createBufferStrategy(2);
backBuffer = this.getBufferStrategy();
bg = new ImageIcon(getClass().getResource("/bg.png")).getImage();
// init variables
gameOver = false;
// Generating stars
generateStars();
// Init spaceship
ship = new Ship(25,36,"ship.png");
// Init loop
gameLoop();
}
public void initWindow(){
JFrame window = new JFrame("Asteroids");
setPreferredSize(dimension);
window.add(this);
window.pack();
window.setResizable(false);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.requestFocus();
}
public float lerp(float starGoal, float vel, float speed) {
return starGoal + speed * (vel - starGoal);
}
public void update() {
if(keyDownMap.containsKey(KeyEvent.VK_ESCAPE)){
gameOver = false;
System.exit(0);
}
for(Star s: stars) {
s.posx += lerp(this.starGoalX, s.velX, Config.lerpSpeed);
s.velX += this.starGoalX * Config.lerpSpeed;
s.posy += lerp(this.starGoalY, s.velY, Config.lerpSpeed);
s.velY += this.starGoalY * Config.lerpSpeed;
checkPos(s);
s.update();
}
}
public void checkPos(Star s) {
if(s.posx < -s.width)
s.posx = Config.WINDOW_WH[0]-s.width;
else if(s.posx > Config.WINDOW_WH[0])
s.posx = 0;
if(s.posy < -s.height)
s.posy = Config.WINDOW_WH[1]-s.height;
else if(s.posy > Config.WINDOW_WH[1])
s.posy = 0;
}
public void render(){
Graphics2D g = (Graphics2D) backBuffer.getDrawGraphics();
if (!backBuffer.contentsLost()) {
g.drawImage(this.bg,0,0,Config.WINDOW_WH[0], Config.WINDOW_WH[1], null);
// Draw Stars
g.setColor(Color.WHITE);
for(Star s: stars)
g.fillOval(s.posx - (s.width/2), s.posy - (s.height/2), s.width, s.height);
// Draw ship
g.drawImage(
this.ship.getImage(),
this.ship.posx, this.ship.posy,
this.ship.width, this.ship.height, null);
backBuffer.show();
g.dispose();
}
}
public void generateStars() {
for(int i = 0;i < 50;i++) {
int starX = new Random().nextInt(Config.WINDOW_WH[0]+100)+5;
int starY = new Random().nextInt(Config.WINDOW_WH[1]+100)+5;
stars.add(new Star(starX, starY));
}
}
public void gameLoop(){
while(!gameOver){
update();
render();
try{ Thread.sleep(20);}catch(Exception e){};
}
}
public static void main(String[] args) {
new Main();
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT) this.starGoalX = Config.lerpSpeed;
if(e.getKeyCode() == KeyEvent.VK_RIGHT) this.starGoalX = -Config.lerpSpeed;
if(e.getKeyCode() == KeyEvent.VK_UP) this.starGoalY = Config.lerpSpeed;
if(e.getKeyCode() == KeyEvent.VK_DOWN) this.starGoalY = -Config.lerpSpeed;
keyDownMap.put(e.getKeyCode(), true);
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT
|| e.getKeyCode() == KeyEvent.VK_RIGHT) this.starGoalX = 0;
if(e.getKeyCode() == KeyEvent.VK_UP
|| e.getKeyCode() == KeyEvent.VK_DOWN) this.starGoalY = 0;
keyDownMap.remove(e.getKeyCode());
}
}
Star.java
package asteroids;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.KeyEvent;
import java.awt.geom.Ellipse2D;
import java.util.HashMap;
import java.util.Random;
public class Star {
int width, height;
int posx, posy;
float velX, velY, velGoalX, velGoalY;
/** CONSTRUCTOR **/
public Star(int x, int y) {
int rand = new Random().nextInt(Config.STAR_SIZES.length);
width = Config.STAR_SIZES[rand];
height = Config.STAR_SIZES[rand];
posx = x;
posy = y;
}
public void update() {
// pass
}
}
Ship.java
package asteroids;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import javax.swing.ImageIcon;
public class Ship {
public int posx, posy;
public int width, height;
private Image image;
public Ship(int w, int h, String img) {
this.posx = Config.WINDOW_WH[0]/2;
this.posy = Config.WINDOW_WH[1]/2;
this.width = w;
this.height = h;
this.image = new ImageIcon(getClass().getResource("/"+img)).getImage();
}
public Image getImage() {
return this.image;
}
public void setPosx(int x) {posx = x;}
public void setPosy(int y) {posy = y;}
public void setImg(Image img) {
this.image = img;
}
public void update(HashMap keyDownMap) {
// pass
}
}
Config.java
package asteroids;
import java.awt.Color;
public class Config {
// MAIN CANVAS SETTINGS
public static int[] WINDOW_WH = {500, 500};
public static String WINDOW_BG_IMG = "";
public static Color WINDOW_BG_CLR = new Color(40, 42, 45);
// OBJECT SETTINGS
public static int[] STAR_SIZES = {10,5,8,3,7};
public static float lerpSpeed = 0.8f;
}
I don't understand why after i get over the first half of a ball that when the ball I control hits the right half of a moving ball that it doesn't activate the collision code to kill the program.
I have it set to measure the distance between the ball that you control then the ball that is passing by. I am still confused why I can land on the second half of the ball without the program closing itself out.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import javax.swing.ImageIcon;
public class JumpingSprite extends JPanel implements KeyListener {
//public int yPos;
public static void main(String[] args) {
new JumpingSprite();
}
public JumpingSprite() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Mr.Baird");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
TestPane testPane = new TestPane();
frame.add(testPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
int getyPos(){
return yPos;
}
protected static final int SPRITE_HEIGHT = 60;
protected static final int SPRITE_WIDTH = 60;
private float vDelta;
private float rbDelta;
private float rbDegDelta;
public int yPos;
private float gDelta; // Gravity
private Timer engine;
private boolean bounce = false;
int ballx = 1000;
int bally = 500;
int ballw = 100;
int ballh = 100;
int ball2x = 1500;
int ball2y = 480;
int ball2w = 120;
int ball2h = 120;
int ball3x = 2500;
int ball3y = 0;
int ball3w = 600;
int ball3h = 600;
public TestPane() {
yPos = getPreferredSize().height - SPRITE_HEIGHT;
vDelta = 0;
gDelta = 3f;
rbDegDelta = 30f; //affects how many bounces mang
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "jump");
am.put("jump", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
if (yPos + SPRITE_HEIGHT == getHeight()) {
vDelta = -40 ;
rbDelta = vDelta;
bounce = true;
}
}
});
engine = new Timer(15, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int height = getHeight();
if (height > 0) {
if (bounce) {
yPos += vDelta;
vDelta += gDelta;
// If the sprite is not on the ground
if (yPos + SPRITE_HEIGHT >= height) {
// put on le ground
yPos = height - SPRITE_HEIGHT;
if (rbDelta >= 0) {
// Stop bouncin
bounce = false;
} else {
// Add the re-bound degregation delta to the re-bound delta
rbDelta += rbDegDelta;
// Set the vDelta...
vDelta = rbDelta;
}
}
}
}
if (Math.sqrt((Math.pow((500 - (ballx)), 2)) + Math.pow((yPos - bally), 2)) <= (50)) {
System.exit(0);
}
if (Math.sqrt((Math.pow((500 - (ball2x)), 2)) + Math.pow((yPos - ball2y), 2)) <= (60)) {
System.exit(0);
}
if (Math.sqrt((Math.pow((500 - (ball3x)), 2)) + Math.pow((yPos - ball3y), 2)) <= (350)) {
System.exit(0);
}
ballx = ballx-8;
ball2x = ball2x-8;
ball3x = ball3x-8;
repaint();
}
});
engine.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1000, 600);
}
#Override
protected void paintComponent(Graphics g) {
//addin all them pretty colors to le object
super.paintComponent(g);
//Graphics2D g2d = (Graphics2D) g.create();
g.setColor(Color.black);
g.fillRect(0,0,1000,1000);
int width = getWidth() - 1;
int xPos = (width - SPRITE_WIDTH) / 2;
g.setColor(Color.blue);
g.fillOval(xPos, yPos, SPRITE_WIDTH, SPRITE_HEIGHT);
//g.dispose();
g.setColor(Color.red);
g.fillOval(ballx, bally, ballw, ballh);
g.setColor(Color.green);
g.fillOval(ball2x, ball2y, ball2w, ball2h);
g.setColor(Color.pink);
g.fillOval(ball3x, ball3y, ball3w, ball3h);
}
}
#Override
public void keyPressed(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
The general solution to this problem is to calculate the (Euclidean) distance between the centers of both balls/circles, and determine if that length is less than their combined radii. The other way you could do this is to create java.awt.Areas from your Shapes, and use Area.intersect(Area) != null;
So I've pretty much thrown together a basic game in java by following a bunch of different tutorials - the problem is i cant manage to figure out how to get my sprite to move in different directions. Here is the code for my main
package com.game.src.main;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
public static final int WIDTH = 850;
public static final int HEIGHT = 650;
public static final int SCALE = 1;
public final String TITLE = "Racing Game!";
static ServerSocket serverSocket;
static Socket socket;
static DataOutputStream out;
private boolean running = false;
private Thread thread;
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT,BufferedImage.TYPE_INT_RGB);
private BufferedImage spriteSheet = null;
private BufferedImage spriteSheet2 = null;
private BufferedImage background = null;
private BufferedImage MenuBackground = null;
private Player p;
private Player2 p2;
private Menu menu;
public static enum STATE {
MENU,
GAME
};
public static STATE State = STATE.MENU;
public void init() {
BufferedImageLoader loader = new BufferedImageLoader();
try {
spriteSheet = loader.loadImage("/Sprite_Sheet.png");
background = loader.loadImage("/Track.png");
MenuBackground = loader.loadImage("/MenuBG.fw.png");
}
catch (IOException e) {
e.printStackTrace();
}
menu = new Menu();
addKeyListener(new KeyInput(this));
this.addMouseListener(new MouseInput());
p = new Player(365, 500, this);
p2 = new Player2(365, 550, this);
}
private synchronized void start() {
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
private synchronized void stop() {
if(!running)
return;
running = false;
try {
thread.join();
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.exit(1);
}
public void run() {
init();
long lastTime = System.nanoTime();
final double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
int updates = 0;
int frames = 0;
long timer = System.currentTimeMillis();
while(running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
if(delta >= 1) {
tick();
updates++;
delta--;
}
render();
frames++;
if(System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println(updates + " FPS, TICKS " + frames);
updates = 0;
frames = 0;
}
}
stop();
}
private void tick() {
if(State == STATE.GAME){
p.tick();
p2.tick();
}
}
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if(bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
g.drawImage(MenuBackground, 0, 0, null);
if(State == STATE.GAME){
//Drawing the main games background
g.drawImage(background, 0, 0, null);
p.render(g);
p2.render(g);
}
else if(State == STATE.MENU){
menu.render(g);
}
g.dispose();
bs.show();
}
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
if(State == STATE.GAME){
if(key == KeyEvent.VK_RIGHT){
p.setVelX(5);
}
if(key == KeyEvent.VK_D){
p2.setVelX2(5);
}
else if(key == KeyEvent.VK_LEFT) {
p.setVelX(-5);
}
else if(key == KeyEvent.VK_A) {
p2.setVelX2(-5);
}
else if(key == KeyEvent.VK_DOWN) {
p.setVelY(5);
}
else if(key == KeyEvent.VK_S) {
p2.setVelY2(5);
}
else if(key == KeyEvent.VK_UP) {
p.setVelY(-5);
}
else if(key == KeyEvent.VK_W) {
p2.setVelY2(-5);
}
}
}
public void keyReleased(KeyEvent e){
int key = e.getKeyCode();
if(key == KeyEvent.VK_RIGHT){
p.setVelX(0);
}
if(key == KeyEvent.VK_D){
p2.setVelX2(0);
}
else if(key == KeyEvent.VK_LEFT) {
p.setVelX(0);
}
else if(key == KeyEvent.VK_A) {
p2.setVelX2(0);
}
else if(key == KeyEvent.VK_DOWN) {
p.setVelY(0);
}
else if(key == KeyEvent.VK_S) {
p2.setVelY2(0);
}
else if(key == KeyEvent.VK_UP) {
p.setVelY(0);
}
else if(key == KeyEvent.VK_W) {
p2.setVelY2(0);
}
}
public static void main(String args[]) throws Exception {
Game game = new Game();
game.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
JFrame frame = new JFrame(game.TITLE);
frame.add(game);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
game.start();
System.out.println("Starting server....");
serverSocket = new ServerSocket(7777);
System.out.println("Server started");
socket = serverSocket.accept();
System.out.println("Connecting from: " + socket.getInetAddress());
out = new DataOutputStream(socket.getOutputStream());
out.writeUTF("This is a test of Java Sockets");
System.out.println("Data has been sent");
}
public BufferedImage getSpriteSheet() {
return spriteSheet;
}
public BufferedImage getSpriteSheet2() {
return spriteSheet2;
}
}
This is my player class
package com.game.src.main;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
public class Player {
private double x;
private double y;
private double velX = 0;
private double velY = 0;
private BufferedImage player;
BufferedImageLoader loader = new BufferedImageLoader();
BufferedImage SpriteSheet = null;
public Player(double x, double y, Game game) {
this.x = x;
this.y = y;
//New instance of Sprite sheet - reading from buffered image loader
SpriteSheet ss = new SpriteSheet(game.getSpriteSheet());
player = ss.grabImage(1, 1, 50, 50);
try {
SpriteSheet = loader.loadImage("/Sprite_Sheet.png");
}
catch(Exception e) {
e.printStackTrace();
}
}
public void tick() {
x+=velX;
y+=velY;
//Adding basic collision
if(x < 0 + 50) {
x = 0 + 50;
}
if(x >= 850 - 100) {
x = 850 - 100;
}
if(y < 0 + 100) {
y = 0 + 100;
}
if(y >= 650 - 100){
y = 650 - 100;
}
}
public void render(Graphics g){
//Draw Track
Color c1 = Color.green;
g.setColor( c1 );
g.fillRect( 150, 200, 550, 300 ); //grass
Color c2 = Color.black;
g.setColor( c2 );
g.drawRect(50, 100, 750, 500); // outer edge
g.drawRect(150, 200, 550, 300); // inner edge
Color c3 = Color.yellow;
g.setColor( c3 );
g.drawRect( 100, 150, 650, 400 ); // mid-lane marker
Color c4 = Color.white;
g.setColor( c4 );
g.drawLine( 425, 500, 425, 600 ); // start line
g.drawImage(player, (int)x, (int)y, null);
}
public double getX(Graphics g){
return x;
}
public double getY(){
return y;
}
public void setX(double x){
this.x = x;
}
public void setY(double y){
this.y = y;
}
public void setVelX(double velX){
this.velX = velX;
}
public void setVelY(double velY){
this.velY = velY;
}
}
I have two players in this game but i'm really stuck on how i can change the sprites direction by 22.5% in a desired direction so if i pressed the up key for player 1 it would rotate my car 22.5% north etc. I have a sprite sheet with 16 sprites for each player for every change in angle by 22.5% This is really confusing me and i'm not sure how i can implement this,
Thanks for taking the time to look
This is a basic example of spinning a sprite
What this is maintain's a virtual state which the Player object inspects in order to determine how it should be changed accordingly. This separates the action from the result, meaning that it would be possible to substitute the action (arrow up key) with some other action, but still obtain the same result.
This example also uses the key bindings API, which doesn't suffer from the same focus related issues that KeyListener does, but this is a pure Swing API and won't be compatiable with Canvas, but is a nice demonstration ;)
The real magic occurs in the characters paint method...
public void paint(Graphics2D g2d) {
Graphics2D g = (Graphics2D) g2d.create();
AffineTransform at = new AffineTransform();
at.translate(x, y);
at.rotate(Math.toRadians(angle), character.getWidth() / 2, character.getHeight() / 2);
g.transform(at);
g.drawImage(character, 0, 0, null);
}
Basically, this creates a AffineTransformation which is then compounded to produce the result we need. That is, first it's anchor position is translated to the characters x/y position and then rotated about the characters center point. Because it's been translated, we can simply paint the character at 0x0. This much easier then try to calculate the characters rotation anchor somewhere else in virtual space - IMHO
The character is rotated by pressing either the Up or Down arrow keys. While pressed, the character will continue to rotate, this is a feature of the example for demonstration purpose.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RotateCharater {
public static void main(String[] args) {
new RotateCharater();
}
public RotateCharater() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private DefaultState state;
private Player player;
public TestPane() {
player = new Player();
state = new DefaultState();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "upKeyPressed");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "upKeyReleased");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "downKeyPressed");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "downKeyReleased");
ActionMap am = getActionMap();
am.put("upKeyPressed", new UpKeyAction(state, true));
am.put("upKeyReleased", new UpKeyAction(state, false));
am.put("downKeyPressed", new DownKeyAction(state, true));
am.put("downKeyReleased", new DownKeyAction(state, false));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
player.update(state);
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
player.paint(g2d);
g2d.dispose();
}
public class UpKeyAction extends AbstractAction {
private DefaultState state;
private boolean pressed;
public UpKeyAction(DefaultState state, boolean pressed) {
this.state = state;
this.pressed = pressed;
}
#Override
public void actionPerformed(ActionEvent e) {
state.setUpKeyPressed(pressed);
}
}
public class DownKeyAction extends AbstractAction {
private DefaultState state;
private boolean pressed;
public DownKeyAction(DefaultState state, boolean pressed) {
this.state = state;
this.pressed = pressed;
}
#Override
public void actionPerformed(ActionEvent e) {
state.setDownKeyPressed(pressed);
}
}
}
public interface State {
public boolean isUpKeyPressed();
public boolean isDownKeyPressed();
}
public class DefaultState implements State {
private boolean upKeyPressed;
private boolean downKeyPressed;
public boolean isDownKeyPressed() {
return downKeyPressed;
}
public boolean isUpKeyPressed() {
return upKeyPressed;
}
public void setDownKeyPressed(boolean downKeyPressed) {
this.downKeyPressed = downKeyPressed;
upKeyPressed = false;
}
public void setUpKeyPressed(boolean upKeyPressed) {
this.upKeyPressed = upKeyPressed;
downKeyPressed = false;
}
}
public class Player {
private BufferedImage character;
private int x = 100 - 32, y = 100 - 32;
private double angle;
public Player() {
try {
character = ImageIO.read(getClass().getResource("/Character.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void paint(Graphics2D g2d) {
Graphics2D g = (Graphics2D) g2d.create();
AffineTransform at = new AffineTransform();
at.translate(x, y);
at.rotate(Math.toRadians(angle), character.getWidth() / 2, character.getHeight() / 2);
g.transform(at);
g.drawImage(character, 0, 0, null);
}
public void update(State state) {
if (state.isUpKeyPressed()) {
angle -= 22.5;
} else if (state.isDownKeyPressed()) {
angle += 22.5;
}
}
}
}
Remember, this is just an example used to present the concept ;)
I am trying to make a program that has a moving ball and a platform that it will sit on. I am new too java and I cant figure out how to detect when 2 swing objects are overlapping. My code it below and I am wondering what the best way is to detect overlapping objects.
KeyDemo.java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class KeyDemo
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
JPanel panel = new JPanel();
LayoutManager overlay = new OverlayLayout(panel);
panel.setLayout(overlay);
final int FRAME_WIDTH = 800;
final int FRAME_HEIGHT = 600;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("Move the Ball");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final WallComponent wc1 = new WallComponent(400, 400);
final BallComponent bc = new BallComponent(400, 300);
panel.add(wc1);
panel.add(bc);
frame.add(panel);
KeyboardController kc = new KeyboardController(bc);
frame.addKeyListener(kc);
frame.setVisible(true);
class AnimationListener implements ActionListener{
public void actionPerformed(ActionEvent event){
bc.tick();
//wc1.checkOverlap(bc);
}
}
ActionListener aListener = new AnimationListener();
final Timer timer = new Timer(1, aListener);
timer.start();
}
}
KeyboardController.java:
import java.awt.*;
import java.awt.event.*;
public class KeyboardController implements KeyListener
{
BallComponent bComp;
public KeyboardController(BallComponent t)
{
bComp = t;
}
/** Handle the key pressed event from the text field. */
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == 38)
{
System.out.println("Pressed Up!");
bComp.moveUp();
}
if(keyCode == 37)
{
System.out.println("Pressed Left!");
bComp.moveLeft();
}
if(keyCode == 39)
{
System.out.println("Pressed Right!");
bComp.moveRight();
}
if(keyCode == 40)
{
System.out.println("Pressed Down!");
bComp.moveDown();
}
}
/** Handle the key released event from the text field. */
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == 38)
{
System.out.println("Released Up!");
bComp.stopY();
}
if(keyCode == 37)
{
System.out.println("Released Left!");
bComp.stopX();
}
if(keyCode == 39)
{
System.out.println("Released Right!");
bComp.stopX();
}
if(keyCode == 40)
{
System.out.println("Pressed Down!");
bComp.stopY();
}
}
public void keyTyped(KeyEvent e) {
}
}
BallComponent.java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class BallComponent extends JComponent
{
int xSpeed;
int ySpeed;
int x;
int y;
public BallComponent(int x, int y)
{
super();
this.x = x;
this.y = y;
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
Ellipse2D.Double ball = new Ellipse2D.Double(x-10,y-10,10,10);
g2.setColor(Color.RED);
g2.fill(ball);
g2.draw(ball);
}
public void moveLeft()
{
xSpeed=-1;
}
public void moveRight()
{
xSpeed=1;
}
public void moveUp()
{
ySpeed=-1;
}
public void moveDown()
{
ySpeed=1;
}
public void tick()
{
x=x+xSpeed;
y=y+ySpeed;
repaint();
}
public void stopY()
{
ySpeed=0;
}
public void stopX()
{
xSpeed=0;
}
}
WallComponent.java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class WallComponent extends JComponent
{
int x;
int y;
public WallComponent(int x, int y)
{
super();
this.x = x;
this.y = y;
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
Rectangle wall = new Rectangle(x-40,y-40,40,40);
g2.setColor(Color.YELLOW);
g2.fill(wall);
g2.draw(wall);
}
public void checkOverlap(BallComponent bc){
if (this.contains(bc.getLocation())){
bc.stopY();
bc.stopX();
}
}
}
All Swing components have a concept of "bounds". This is a rectangular area within which they are "drawn".
If you are controlling the size and position correctly, you should be able to use the contains method of the Rectangle which is returned from calling Component#getBounds
So you checkOverlap method could look like...
public void checkOverlap(BallComponent bc){
if (getBounds().intersects(bc.getBounds())){
bc.stopY();
bc.stopX();
}
}
You will also want to make sure that you are calling super.paintComponent before performing any custom painting, espeically when using components that extend from JComponent. This will ensure that the Graphics context is prepared for painting correctly...
Updated
There's a cascade of issues. Basically, instead of positing the components within the parent container yourself (which is how I thought you had done it), you've laid each component out to fill the parent container and only "painted" the objects...This makes life more difficult
Instead, if you are going to use components, I would use a null layout (or even possibly use a JLayeredPane as the parent container).
I would then change the physical position of the components, for example...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestGame {
public static void main(String[] args) {
new TestGame();
}
public TestGame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setLayout(null);
final int FRAME_WIDTH = 800;
final int FRAME_HEIGHT = 600;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setTitle("Move the Ball");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final WallComponent wc1 = new WallComponent(400, 400);
final BallComponent bc = new BallComponent(400, 300);
panel.add(wc1);
panel.add(bc);
frame.add(panel);
KeyboardController kc = new KeyboardController(bc);
frame.addKeyListener(kc);
frame.setVisible(true);
class AnimationListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
bc.tick();
wc1.checkOverlap(bc);
}
}
ActionListener aListener = new AnimationListener();
final Timer timer = new Timer(1, aListener);
timer.start();
}
});
}
public class KeyboardController implements KeyListener {
BallComponent bComp;
public KeyboardController(BallComponent t) {
bComp = t;
}
/**
* Handle the key pressed event from the text field.
*/
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == 38) {
System.out.println("Pressed Up!");
bComp.moveUp();
}
if (keyCode == 37) {
System.out.println("Pressed Left!");
bComp.moveLeft();
}
if (keyCode == 39) {
System.out.println("Pressed Right!");
bComp.moveRight();
}
if (keyCode == 40) {
System.out.println("Pressed Down!");
bComp.moveDown();
}
}
/**
* Handle the key released event from the text field.
*/
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == 38) {
System.out.println("Released Up!");
bComp.stopY();
}
if (keyCode == 37) {
System.out.println("Released Left!");
bComp.stopX();
}
if (keyCode == 39) {
System.out.println("Released Right!");
bComp.stopX();
}
if (keyCode == 40) {
System.out.println("Pressed Down!");
bComp.stopY();
}
}
public void keyTyped(KeyEvent e) {
}
}
public class BallComponent extends JComponent {
int xSpeed;
int ySpeed;
public BallComponent(int x, int y) {
super();
setBounds(x, y, 10, 10);
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Ellipse2D.Double ball = new Ellipse2D.Double(0, 0, 9, 9);
g2.setColor(Color.RED);
g2.fill(ball);
g2.draw(ball);
}
public void moveLeft() {
xSpeed = -1;
}
public void moveRight() {
xSpeed = 1;
}
public void moveUp() {
ySpeed = -1;
}
public void moveDown() {
ySpeed = 1;
}
public void tick() {
int x = getX() + xSpeed;
int y = getY() + ySpeed;
setLocation(x, y);
repaint();
}
public void stopY() {
ySpeed = 0;
}
public void stopX() {
xSpeed = 0;
}
}
public class WallComponent extends JComponent {
public WallComponent(int x, int y) {
super();
setBounds(x, y, 40, 40);
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Rectangle wall = new Rectangle(0, 0, 40, 40);
g2.setColor(Color.YELLOW);
g2.fill(wall);
g2.draw(wall);
}
public void checkOverlap(BallComponent bc) {
System.out.println(" me: " + getBounds());
System.out.println("you: " + bc.getBounds());
if (getBounds().intersects(bc.getBounds())) {
bc.stopY();
bc.stopX();
}
}
}
}
Now, you could use "painted" objects, but in that case I would have a virtual concept of a Ball and Wall which you could paint within a single component. These objects would need to provide information about there position and size, which you could, again, check using Rectangle#intersects...
Generally, just try to make a "bounding box" for your objects. This will be the invisible rectangle that goes with the object. Then just do
if(rectangle1.intersects(rectangle2)) ...
The intersects method only works with rectangles, and that's why you need a bounding box.