I'm trying to make impassable walls on the edge of my screen (JFrame). So when I move my image to the left and it touches the left side of the frame, it forces the image to not move. I tried various things, but I just can't seem to find the right code for it, so I'm wondering how to do it based around my code.
import javax.swing.*;
import java.awt.event.*;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.net.URL;
public class MovingImages extends JPanel implements KeyListener, ActionListener
{
Timer t = new Timer(5, this);
int x = 0, y = 0; //coordinates for the image
int imageScaleX = 100, imageScaleY = 100; //scale the size of the image
int velX = 0, velY = 0;
//--------------------------------------------------------------------------------------- DISPLAYING IMAGE
public MovingImages()
{
t.start();
addKeyListener(this); //enables the KeyListener so keys can be pressed
setFocusable(true);
}
/** This code is only used for importing the image and runs the program even when there is no image
* #param path is a String that is used to represent the the name or where your file is
* #return is the tempImage which is the image that the program found
*/
public Image getImage(String path)
{
Image tempImage = null;
try
{
URL imageURL = MovingImages.class.getResource(path); //finds where the image is
tempImage = Toolkit.getDefaultToolkit().getImage(imageURL); //loads image from file
}
catch (Exception e)
{
}
return tempImage;
}
/** This code is used to display the image in specified coordinates
* #param g is a variable that uses the Graphics method
*/
public void paint(Graphics g)
{
Image image = getImage("sprite.png"); //choose the file for your image
super.paintComponent(g); //everytime the image moves, it clears the previous image
Graphics2D g2 = (Graphics2D) g; //converts graphics into 2D
g2.drawImage(image, x, y, imageScaleX, imageScaleY, this); //draws image in specific coordinates
}
//--------------------------------------------------------------------------------------- KEYBOARD FUNCTIONS
public void actionPerformed(ActionEvent e)
{
x += velX;
y += velY;
repaint();
}
public void up()
{
velY = -2;
}
public void down()
{
velY = 2;
}
public void left()
{
velX = -2;
}
public void right()
{
velX = 2;
}
public void keyPressed(KeyEvent e)
{
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP)
{
up();
}
if (keyCode == KeyEvent.VK_DOWN)
{
down();
}
if (keyCode == KeyEvent.VK_LEFT)
{
left();
}
if (keyCode == KeyEvent.VK_RIGHT)
{
right();
}
}
public void keyTyped(KeyEvent e)
{
}
public void keyReleased(KeyEvent e)
{
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP)
{
velY = 0;
}
if (keyCode == KeyEvent.VK_DOWN)
{
velY = 0;
}
if (keyCode == KeyEvent.VK_LEFT)
{
velX = 0;
}
if (keyCode == KeyEvent.VK_RIGHT)
{
velX = 0;
}
}
//--------------------------------------------------------------------------------------- MAIN
public static void main(String args[])
{
MovingImages s = new MovingImages();
JFrame f = new JFrame();
f.add(s);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(1280, 720);
}
}
The following answer explains the general principle behind forcing objects to stay within their container. Within your program's event loop you are updating an object's x and y coordinates, either directly in response to keyboard input or in a timer loop based on a saved velocity. In either case the basic principle is the same:
Detect when an object's edge bumps up against the container's boundary and don't apply any changes to the object coordinate that would move it so it is partially or completely outside the container.
The following pseudocode describes what has to happen every time you go to update an object's position. I show only the code for horizontal movement, vertical movement is left as an exercise. I assume the object's "position" is the coordinate of the lower left corner of its bounding box.
int left_edge = pos_x;
int right_edge = pox_x + width;
if (velocity_x < 0)
pos_x += left_edge > 0 ? velocity_x : 0;
else if (velocity_x > 0)
pos_x += right_edge < container_width ? velocity_x : 0;
Some questions I have not addressed which are left as an exercise:
Vertical movement
What happens to velocity when the object bumps against a wall. Does (a) the object continue to "try" to move or (b) does the velocity in that direction drop to zero? The first option (a) might apply for instance if there's a barrier of some kind in the middle of the container. The object could bump up against it and stop horizontal movement while still having vertical movement and when eventually clearing the barrier vertically, then continue also moving horizontally.
If velocity > 1 the above code can result in ending up partially outside the container (i.e. you start at x==1 with velocity==-2). You will need to enhance the code for this case, keeping in mind your answer to item 2 above.
Related
Being new to coding, I watched a video on how to create Pong. That went well, and as a result I wanted to try and recreate Brick Breaker using some of the coding techniques that were used for Pong. So far I have the ball, paddle, and the base of the game. However, the ball does not collide properly with the paddle, instead of bouncing of it passes through.
Code for base game:
import java.applet.Applet;
import java.awt.Color;
import java.awt.Image;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Breaker extends Applet implements Runnable, KeyListener{
final int WIDTH = 600, HEIGHT= 400;
Thread thread;
Graphics gfx;
Image img;
Ball b1;
Player p1;
public void init() {
this.resize(WIDTH, HEIGHT);
this.addKeyListener(this);
b1 = new Ball();
p1 = new Player(1);
img = createImage(WIDTH,HEIGHT);
gfx = img.getGraphics();
thread = new Thread(this);
thread.start();
}
public void paint(Graphics g) {
gfx.setColor(Color.black);
gfx.fillRect(0, 0, WIDTH, HEIGHT);
b1.draw(gfx);
p1.draw(gfx);
g.drawImage(img, 0, 0, this);
}
public void update (Graphics g) {
paint(g);
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT){
p1.setLeftAccel(true);
}
else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
p1.setRightAccel(true);
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT){
p1.setLeftAccel(false);
}
else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
p1.setRightAccel(false);
}
}
#Override
public void run() {
for(;;) {
p1.move();
b1.move();
b1.checkPlayerCollision(p1);
repaint();
getToolkit().sync();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
Ball:
import java.awt.Graphics;
import java.awt.Color;
public class Ball {
int score;
double xVel, yVel, x, y;
public Ball() {
x= 350;
y = 250;
xVel= 0;
yVel = 1;
}
public void draw(Graphics g) {
g.setColor(Color.white);
g.fillOval((int)x - 10, (int)y - 10, 20, 20);
}
public void checkPlayerCollision(Player p1) {
if (x <= 50) {
if(x >= p1.getX() && x <= p1.getX() + 10)
xVel = -xVel;
}
else if (x >= 680) {
xVel = -xVel;
}
}
public void move() {
x += xVel;
y += yVel;
if (y < 10) //Bounce at top side of screen
yVel = -yVel;
if (x < 10) // Bounce at left side of screen
xVel = -xVel;
}
public int getX() {
return (int)x;
}
public int getY() {
return (int)y;
}
}
Player:
import java.awt.Color;
import java.awt.Graphics;
public class Player implements Paddle {
double x, xVel;
boolean leftAccel, rightAccel;
int player, y;
public Player(int player) {
leftAccel = false; rightAccel = false;
x=260; xVel=0;
}
#Override
public void draw(Graphics g) {
g.setColor(Color.white);
g.fillRect((int)x, 380, 80, 10);
}
#Override
public void move() {
if(leftAccel){
xVel -= 2;
}
else if (rightAccel) {
xVel += 2;
}
else if (!leftAccel && !rightAccel) {
xVel = 0;
}
if(xVel >= 5) {
xVel = 5;
}
else if (xVel <= -5) {
xVel = -5;
}
x += xVel;
if(x < 0)
x=0; //Collision with left wall
if(x > 520)
x = 520; //Collision with right wall
}
public void setLeftAccel(boolean input) {
leftAccel = input;
}
public void setRightAccel(boolean input) {
rightAccel = input;
}
#Override
public int getX() {
return (int)x;
}
}
Paddle:
import java.awt.Graphics;
public interface Paddle {
public void draw(Graphics g);
public void move();
public int getX();
}
I don't completely understand hit detection yet, so I just messed with what was used for pong, however, that doesn't work (and I'm sure it might look weird).
Collision detection can be hard to wrap your head around sometimes. What really helps me is to draw on a piece of paper the things I need to check for and write the checks in code one by one. It's also a good idea to keep your axes in mind, it's really easy to mix up an x and a y, but they will have an important effect on gameplay.
My eye was drawn to your checkPlayerCollision function as it seemed a little off, I have changed some checks around and commented what each check/function is doing.
public void checkPlayerCollision(Player p1) {
if (
// Is the ball at or below paddle height?
y <= 50
// AND Is the ball right of the left side of the paddle?
&& x >= p1.getX()
// AND Is the ball left of the right side of the paddle?
&& x <= p1.getX() + 10
) {
// Collision with the paddle!
// (Ball is lower than y=50 and between left and right side of the paddle!)
// As we want the ball to go back up, we will be changing its velocity
// along the Y-axis.
yVel -= yVel;
} else if (x >= 680) {
// This checks whether the ball went too far to the right..?
xVel -= xVel;
}
}
Best tip I can give you: grab a piece of paper and just draw a simple grid or graph and use that to draw out different things you need to check. Be sure to label your (0,0) point so when you work with the different borders, you know which ones are 0 (usually top and left borders) and which ones are equal to width and height of the canvas.
So I am trying to build a top down space shooter in java.
I am fairly new but I have a good grasp on it having perfected making pong. My main problem is that I can't seem to get rotation down.
I want to be able to press right or left on the arrow keys and have, say a basic rectangle, rotate around its center in the direction the user is inputting.
Once I have that down I want to be able to press forward or backward on the arrow keys to make it go in the direction it is currently facing.
Everything I have tried so far affected everything in the frame instead of just a singular object. Having come from as2, rotation and objects are very different in java.
Can someone help explain to me how I would do this?
package spaceroyalgame;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.geom.AffineTransform;
public class SpaceRoyalGame extends JPanel implements KeyListener {
static double shipRotation=0, shipRotationSpeed=0, shipSpeed=0, TOPSPEED= 20;
static int shipy=50, shipx=50, shipWidth = 10, shipHeight = 20;
static int WorldWidth = 700, WorldHeight = 700;
static boolean slowdown = true;
public static void main(String[] args) throws InterruptedException {
SpaceRoyalGame game = new SpaceRoyalGame();
JFrame frame = new JFrame();
frame.add(game);
frame.setSize(WorldWidth,WorldHeight);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addKeyListener(game);
while(true){
game.moveShip();
game.repaint();
Thread.sleep(10);
}
}
public void moveShip(){
if (shipSpeed != 0) {
shipx += shipSpeed;
}
if (shipRotationSpeed != 0) {
shipRotation += shipRotationSpeed;
}
}
public void paint (Graphics g){
super.paint(g);
setBackground(Color.black);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.white);
Rectangle ship = new Rectangle(shipx,shipy,100,50);
g2d.rotate(Math.toRadians(shipRotation));
g2d.draw(ship);
g2d.fill(ship);
}
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
slowdown = false;
if (keyCode == KeyEvent.VK_W) {
//System.out.println("W is pressed");
shipSpeed = -2;
}
if (keyCode == KeyEvent.VK_S) {
//System.out.println("S is pressed");
shipSpeed = 2;
}
if (keyCode == KeyEvent.VK_A) {
System.out.println("A is pressed");
shipRotationSpeed = 1;
shipRotation += shipRotationSpeed * (shipSpeed/TOPSPEED);
}
if (keyCode == KeyEvent.VK_D) {
System.out.println("D is pressed");
shipRotationSpeed = -1;
shipRotation += shipRotationSpeed * (shipSpeed/TOPSPEED);
}
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
shipRotationSpeed = 0;
shipSpeed = 0;
}
}
Try using Vectors. Since 'A' and 'D' keys are modifying your current angle so you should keep a variable to keep track of angle.
From there:
x += speed * cos(θ)
y += speed * sin(θ)
Also if you want to be able to accelerate/decelerate:
Δx = speed * cos(θ) * Δt + 1/2 * acceleration * Δt^2
Δy = speed * * sin(θ) * Δt + 1/2 * acceleration * Δt^2
Δt would be the time between the last frame.
It might be worth taking a look into Physics/Kinematics
package testapplication;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class TestApplication extends JFrame implements Runnable {
int sizex = 800;
int sizey = 650;
int x, y, xDirection, yDirection;
private Image dbImage;
private Graphics dbg;
Image character;
#Override
public void run(){
try{
while(true){
move();
Thread.sleep(5);
}
}
catch(Exception e){
System.out.println("ERROR!!!");
}
}
public void move(){
x += xDirection;
y += yDirection;
if(x <= 0)
x = 0;
if(x >= 778)
x = 778;
if(y <= 22)
y = 22;
if(y >= 628)
y = 628;
}
public void setXDirection(int xdir){
xDirection = xdir;
}
public void setYDirection(int ydir){
yDirection = ydir;
}
Font font = new Font("Arial", Font.BOLD, 30);
public class AL extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
//Key press inputs "WASD"
if(keyCode == KeyEvent.VK_W) {
setYDirection(-1);
}
if(keyCode == KeyEvent.VK_A) {
setXDirection(-1);
}
if(keyCode == KeyEvent.VK_S) {
setYDirection(+1);
}
if(keyCode == KeyEvent.VK_D) {
setXDirection(+1);
}
//end Key press inputs "WASD"
}
#Override
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
//Key release inputs "WASD"
if(keyCode == KeyEvent.VK_W) {
setYDirection(0);
}
if(keyCode == KeyEvent.VK_A) {
setXDirection(0);
}
if(keyCode == KeyEvent.VK_S) {
setYDirection(0);
}
if(keyCode == KeyEvent.VK_D) {
setXDirection(0);
}
//end Key release inputs "WASD"
}
}
public TestApplication() {
//Load images
ImageIcon i = new ImageIcon("C:/Users/Min/Documents/NetBeansProjects/TestApplication/src/testapplication/Untitled-1.png") {};
character = i.getImage();
//Game properties
addKeyListener(new AL());
setTitle("TestApplication");
setSize(sizex, sizey);
setResizable(false);
setVisible(true);
setBackground(Color.LIGHT_GRAY);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x = 30;
y = 628;
}
#Override
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
g.setFont(font);
g.setColor(Color.RED);
g.drawString("Welcome to TESTTEST", 300,125);
g.setColor(Color.RED);
g.drawImage(character, x, y, this);
repaint();
}
public static void main(String[] args) {
TestApplication ta = new TestApplication();
//Threads
Thread t1 = new Thread();
t1.start();
}
}
In my Java code, there is supposed to be an image that moves using the WASD keys. The image shows, yet it will not move. What's wrong?
This is a simple Java code that is supposed to make an image roam around the window with WASD keys. I am not sure what I did wrong in the code, I've double checked and everything looked fine...
First of all, if you need to change the image location while the user presses one of the wsda keys then you need to add 1 and -1 to the current value of x and y ( image location). You just set 1 and -1 which will move the image just one pixel even if, for example, you press the d button multiple times over and over.
You need to change method setXDirection to this (I have added a plus before the equal sign to add xDir value to whatever xDirection is.)
public void setXDirection(int xDir)
{
xDirection += xDir
}
Make the same correction with yDirection (yDirection += yDir)
Second, you don't call your paint method. You have to call it each time your user presses a key (one of wasd ofcourse), so do it at the final line of your keyReleased method.
I hope these two correct your code but I think you need to recheck the code again with much care.
Good luck,
Iman
You forgot to add the Runnable instance to the Thread constructor.
Your main method should be:
public static void main(String[] args) {
TestApplication ta = new TestApplication();
//Threads
Thread t1 = new Thread(ta);
t1.start();
}
i have been trying to make a ball change its direction as any key is pressed. if the ball is moving sideways as the key will be pressed the ball will start moving downward and as it touch the bottom it moves back in upward position...i think i have written the right code , i cant find anything wrong in it.
so can someone please tell me what is problem in this code ?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ASS2 extends JFrame {
public static void main(String args[]) {
ASS2 g = new ASS2();
g.setLayout(new BorderLayout());
g.setSize(500, 500);
MyPanel mp = new MyPanel();
g.add(mp);
mp.setSize(500, 500);
mp.setBackground(Color.black);
//mp.addKeyListener(mp);
g.setVisible(true);
g.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
class MyPanel extends JPanel implements KeyListener {
{
addKeyListener(this);
}
int xpos = 20, ypos = 200;
int xtop = 15, ytop = 15;
int xtemp = 250, ytemp = 250;
int xbot = 450, ybot = 400;
int flag = 1, flag1 = 1;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.white);
g2d.fill(new Ellipse2D.Double(xpos, ypos, 50, 50));
if (xpos < xbot && flag == 1) {
xpos++;
if (xpos == xbot) {
flag = 0;
}
} else if (xpos > xtop && flag == 0) {
xpos--;
if (xpos == xtop) {
flag = 1;
}
}
try {
Thread.sleep(05);
} catch (Exception e) {
}
repaint(1000);
}
public void keyPressed(KeyEvent ae) {
}
public void keyReleased(KeyEvent ae) {
Object t = ae.getKeyCode();
if (t.equals(KeyEvent.VK_DOWN)) {
if (ypos < ybot && flag1 == 1) {
ypos++;
if (ypos == ybot) {
flag1 = 0;
}
} else if (ypos > ytop && flag1 == 0) {
ypos--;
if (ypos == ytop) {
flag1 = 1;
}
}
repaint();
} else if (t.equals(KeyEvent.VK_RIGHT)) {
if (xpos < xbot && flag == 1) {
xpos++;
if (xpos == xbot) {
flag = 0;
}
} else if (xpos > xtop && flag == 0) {
xpos--;
if (xpos == xtop) {
flag = 0;
}
}
repaint();
}
}
}
Welcome to the wonderful world of "why you shouldn't use KeyListeners".
Basically, KeyListener will only raise events when the component that the listener is attached to is focusable AND has focus.
Instead, you should be using Key Bindings which allow you to control the focus level at which they will trigger key events.
Do not use Thread.sleep in any method that is called within the EDT, especially paint methods.
Do not call repaint(1000); inside any paint method or call any method that might trigger a repaint from within paint methods
Do not modify state's within paint methods, paint methods paint, that's all.
Use some kind of "update" thread/process which is responsible for updating the game model and requesting an update to the view. java.swing.Timer is good simple choice to start with. See How to use Swing Timers
When the Swing Timer becomes to limiting for what you are trying to do and you start exploring the use of Threads, don't modify any UI components outside the EDT. See Concurrency in Swing for more details
Always start your programs from within the context of the EDT, see Initial Threads for more details...
I'm teaching myself Java programming with a textbook. An exercise asks you to:
Write a program that draws line segments using the arrow keys. The line starts from the center of the frame and draws toward east, north, west, or south when the right-arrow key, up-arrow key, left-arrow key, or down-arrow key is pressed, as shown in Figure 16.22c.
Figure 16.22c shows a frame with one continuous line flowing in the direction of whichever arrow key the user presses. With each press of an arrow key, the line extends in the direction of the arrow key pressed.
I have gotten as far as drawing a single iteration of the a line, but when I press an arrow key, the original line disappears and a new line is drawn. I know why it does this. And I think I know how to fix it. I was thinking of adding each iteration of a lint into an array (with its corresponding points). I haven't done it yet because it would require rewriting so far.
I figured there might be something I missed in my learning about graphics that could help me perform with task without an array. If there is an easier way, can someone explain it to me.
Here is the code I have so far:
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
public class DrawLinesWithArrowKeys extends JFrame {
DrawLinesPanel panel = new DrawLinesPanel();
/** Constructor */
public DrawLinesWithArrowKeys() {
add(panel);
panel.setFocusable(true);
}
/** Main Method */
public static void main(String[] args) {
JFrame frame = new DrawLinesWithArrowKeys();
frame.setTitle("Draw Lines With Arrow Keys");
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
/** Inner class Draw Lines Panel */
private class DrawLinesPanel extends JPanel {
private int x1Offset = 0;
private int x2Offset = 0;
private int y1Offset = 0;
private int y2Offset = 0;
/* Constructor */
public DrawLinesPanel () {
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
y1Offset = y2Offset;
x1Offset = x2Offset;
y2Offset -= 10;
repaint();
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
y1Offset = y2Offset;
x1Offset = x2Offset;
y2Offset += 10;
repaint();
}
else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
x1Offset = x2Offset;
y1Offset = y2Offset;
x2Offset -= 10;
repaint();
}
else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
x1Offset = x2Offset;
y1Offset = y2Offset;
x2Offset += 10;
repaint();
}
}
});
}
/* Paint line */
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(computeXOne(), computeYOne(), computeXTwo(), computeYTwo());
}
private int computeXOne() {
return (getWidth() / 2) + x1Offset;
}
private int computeXTwo() {
return (getWidth() / 2) + x2Offset;
}
private int computeYOne() {
return (getHeight() / 2) + y1Offset;
}
private int computeYTwo() {
return (getHeight() / 2) + y2Offset;
}
}
}
Accumulate your points in a Shape, such as a Polygon or GeneralPath, seen here. You can draw() the current shape in your implementation of paintComponent(). As an alternative to KeyListener, use key bindings, shown here.