Hi this may be very stupid, but please try to understand that I am an absolute beginner at Java programming. I have been trying to learn it on my own from the internet.
I was trying to make a simple Applet that can move a square using the KeyListener.
First I made a version that can only detect one key at a time. So I looked up a tutorial on YouTube (https://www.youtube.com/watch?v=5UaEUrbpDPE). It used an ArrayList to somehow handle the issue with what was referred to as "Ghosting". The tutorial showed flawless results but my code resulted in some weird problems:
Initially the square moved smoothly in any direction for some time. The square could mainly be moved down and right. After pressing up or left a few times the square could no longer be moved!!!
Can anyone please guide me on what I am doing wrong or how else this could have been accomplished?
Here is the code that I began with (One button at a time detection):
package boxHero;
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class boxGame extends Applet implements KeyListener {
private Rectangle rect;
private int x = 20, y = 20, recW = 50, recH = 50;
public void init() {
setSize(600, 500);
setBackground(Color.BLACK);
this.addKeyListener(this);
rect = new Rectangle (x, y, recW, recH);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.YELLOW);
g2.fill(rect);
}
#Override
public void keyPressed(KeyEvent e) {
// Can't detect more than one key at a time
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
rect.setLocation(rect.x + 10, rect.y);
}
else if(e.getKeyCode() == KeyEvent.VK_LEFT) {
rect.setLocation(rect.x - 10, rect.y);
}
else if(e.getKeyCode() == KeyEvent.VK_UP) {
rect.setLocation(rect.x, rect.y - 10);
}
else if(e.getKeyCode() == KeyEvent.VK_DOWN) {
rect.setLocation(rect.x, rect.y + 10);
}
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
}
Here's the code from the YouTube tutorial:
package boxHero;
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
public class boxGame2 extends Applet implements KeyListener {
private Rectangle rect; // Declaring a rectangle object
private ArrayList<Integer> keysDown;
private int x = 20, y = 20, recW = 50, recH = 50;
public void init() {
setSize(600, 500); // Initial screen size
setBackground(Color.BLACK); // Setting background
this.addKeyListener(this); // Adding KeyListener
keysDown = new ArrayList<Integer>();
rect = new Rectangle (x, y, recW, recH); // Instantiating and Initializing(setting values) for our Rectangle
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
// Graphics for our rectangle
g2.setColor(Color.YELLOW);
g2.fill(rect);
}
public void moveRect() {
int x = rect.x;
int y = rect.y;
if(keysDown.contains(KeyEvent.VK_UP)) {
y -= 10;
}
if(keysDown.contains(KeyEvent.VK_DOWN)) {
y += 10;
}
if(keysDown.contains(KeyEvent.VK_LEFT)) {
x -= 10;
}
if(keysDown.contains(KeyEvent.VK_RIGHT)) {
x += 10;
}
rect.setLocation(x, y);
repaint();
}
#Override
public void keyPressed(KeyEvent e) {
if(!keysDown.contains(e.getKeyCode()) && e.getKeyCode() != 86) {
keysDown.add(new Integer(e.getKeyCode()));
}
moveRect();
}
#Override
public void keyReleased(KeyEvent e) {
keysDown.remove(e);
}
#Override
public void keyTyped(KeyEvent e) {
}
}
The diference between your code and the tutorial is, that the tutorial uses a list of keys that are currently pressed, while you only check out, WHICH key is pressed.
Make an ArrayList of keys like in the tutorial, then add each key when pressed and remove it, as soon as released. Then you can move your rectangle for every key that is contained in your list.
In your keyPressed() event, you add e.getKeyCode() to your keysDown list. But in your keyReleased() event, you only try to remove e from your list, which should result in nothing ever getting removed and all keys remaining pressed. So the reason it doesn't move after a few presses is that you are basically pressing left, right, up and down at once, causing them to cancel each other out.
Also, you should make a habit of using Integer.valueOf(x) instead of new Integer(x), since it caches values in the range of [-128;127], resulting in much better performance when creating wrappers for values in that range.
Related
I've been attempting some sprite animation in with Java and redrawing it, however I can't seem to get my sprite to redraw properly on the Canvas. At first the Problem was that the Previous frames were still there in the back ground of the Canvas when I re-drew it so in order to fix that I added a call to .clearRect(); However while adding the call to that function did fix that problem it caused me to start loosing frames like crazy. I've searched and tried a few things but could find a solution and as near as I can figure .clearRect() is on occasion getting executed after .drawImage(). the Code for my canvas is as Fallows:
package rpg;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
public class Sprite extends Canvas{
/**
*
*/
private BufferedImage img;
private static final long serialVersionUID = 1L;
public Sprite(int width, int height, BufferedImage img){
this.img = img;
setSize(width, height);
}
#Override
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.clearRect(0, 0, this.getWidth(), this.getHeight());
g2d.drawImage(img, 0, 0, null);
g2d.dispose();
}
#Override
public void update(Graphics g) {
paint(g);
}
public void changeSprite(BufferedImage img)
{
this.img = img;
repaint();
}
}
Note: I'm Working with a Transparent background and would like to keep it transparent.
At first the Problem was that the Previous frames were still there in the back ground of the Canvas when I re-drew it so in order to fix that I added a call to .clearRect();
Don't use clearRect(). Instead you should use fillRect(...) to paint the background color of the component.
The following is from the API of the clearRect() method:
Beginning with Java 1.1, the background color of offscreen images may be system dependent. Applications should use setColor followed by fillRect to ensure that an offscreen image is cleared to a specific color.
However, you don't even need to do that. When you override a painting method you need to invoke super.thePaintingMethod(...). In this case you are attempting to override the paint() method so the first statement should be:
super.paint(g);
Then the default painting code of the component will paint the background for you.
Also, this is not Swing painting code. This is AWT code. You really should tag your question properly. We don't know if you are actually trying to do painting using Swing techniques or whether you found old AWT painting code and assume it is the same in Swing.
I'm working with a transparent background
Umm... And why are you trying to use AWT? You still haven't qualified your question. Since you haven't removed the "Swing" tag, I assume you are using Swing.
Using Swing the code would be:
JLabel sprite = new JLabel( new ImageIon(...) );
That's it. One line of code. No need for a custom class.
To change the image you would then just use:
sprite.setIcon( new ImageIcon(...) );
Probably this little example code helps you...
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.EventQueue;
class Player {
public float health;
public float yvel;
public float xvel;
public float x;
public float y;
public BufferedImage image;
public void work(Graphics g, int[] keys) {
g.drawImage(image,(int)x,(int)y,null);
if (keys[0]==1) { //Is the UP-Key pressed
yvel=yvel-1;
}
if (keys[1]==1) { //Is the DOWN-Key pressed
yvel=yvel+1;
}
if (keys[2]==1) { //Is the LEFT-Key pressed
xvel=xvel-1;
}
if (keys[3]==1) { //Is the RIGHT-Key pressed
xvel=xvel+1;
}
x=x+xvel;
y=y+yvel;
xvel=xvel-(xvel/4); //One fourth gets lost
yvel=yvel-(yvel/4); //One fourth gets lost
}
public Player(BufferedImage imagew,float xw, float yw, float healthw) {
x=xw;
y=yw;
image=imagew;
health=healthw;
}
}
public class Game extends JFrame implements KeyListener {
public BufferedImage playerimage;
public Player player;
public int[] keys=new int[4];
public void keyTyped(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
keys[0]=1;
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
keys[1]=1;
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
keys[2]=1;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
keys[3]=1;
}
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
keys[0]=0;
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
keys[1]=0;
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
keys[2]=0;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
keys[3]=0;
}
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
keys[0]=1;
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
keys[1]=1;
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
keys[2]=1;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
keys[3]=1;
}
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
keys[4]=1;
}
}
public Game(){
super("Game");
try {
playerimage = ImageIO.read(getClass().getClassLoader().getResource("player.gif")); //Player Image
} catch(IOException bug) {
System.out.println(bug);
}
player=new Player(playerimage,100,100,100);
addKeyListener(this);
setTitle("Game");
setContentPane(new Pane());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setResizable(false);
setVisible(true);
long start = System.currentTimeMillis();
while (true){
long now = System.currentTimeMillis();
if (now-start > 40) {
System.out.println("FPS : "+Long.toString(1000/(now-start)));
start=now;
framec++;
if (framec==250) {
System.gc();
}
validate();
repaint();
}
}
}
class Pane extends JPanel{
public Pane() {
}
public void paintComponent(Graphics g){
player.work(g,keys);
}
}
public static void main(String args[]){
new Game();
}
}
It draws a controllable player with velocity...
Background should be transparent...
I got the snake running down, now I try to get the keypressed() method to work. I don't think it's listening from the keyboard. My idea is for example if the the down key is pressed, the variable direction is set to 1 and the switch case statement would handle that. I doubt that the direction variable was't read by the switch case.
My main class:
package com.bin.snake;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Game extends JPanel{
boolean playingSnake = true;
Snake snake = new Snake();
public Game() {
addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
snake.keyPressed(e);
}
});
setFocusable(true);
}
public void paint(Graphics g) {// inherit paint method of JPanel class with
// parameter g type Graphics
// parameter g is the object to paint things
super.paint(g); // erase latest image
Graphics2D g2d = (Graphics2D) g; // casting g to Graphics2D type
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// rendering
// image
snake.paint(g2d);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Snake!");
frame.setVisible(true);
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Game game = new Game();
frame.add(game);
while (true) {
game.updateGame();
game.repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void updateGame() {
snake.moveSnake();
}
}
My Snake Class:
package com.bin.snake;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
public class Snake {
private Game game;
int iSnakeLength = 10;
int direction = 1;
final int SIDE = 13;
int[] snakeY = new int[2000];
int[] snakeX = new int[2000];
int xs = 0;
int ys = 0;
public void moveSnake() {
switch (direction) {
case 0:// up
snakeY[0] -=1.5;
break;
case 1:// down
snakeY[0] += 1.5;
break;
case 2:// right
snakeX[0] += 1.5;
break;
case 3:// left
snakeX[0] -=1.5;
break;
}
for (int i = iSnakeLength; i > 0; i--) {
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
}
public void paint(Graphics2D g) {
g.fillRect(snakeX[0], snakeY[0], SIDE, SIDE);
for (int i = 0; i < iSnakeLength; i++) {
g.fillRect(snakeX[i + 1], snakeY[i + 1], SIDE, SIDE);
}
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_DOWN){
direction = 1;
}
if(e.getKeyCode() == KeyEvent.VK_UP){
direction = 0;
}
if(e.getKeyCode() == KeyEvent.VK_LEFT){
direction = 3;
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT){
direction = 2;
}
}
}
I don't think it's listening from the keyboard. My idea
KeyEvents are only dispatched to the component with focus. A JPanel is not focusable by default.
To make a panel focusable you use:
panel.setFocusable( true );
Other comments:
Custom painting is done by overriding the paintComponent(...) method, not the paint() method. Read the Swing tutorial on Custom Painting for more information and examples.
You should NOT be using a KeyListener. Swing was designed to be used with Key Bindings. Read the Swing tutorial on How to Use Key Bindings. You can also check out Motion Using the Keyboard which contains working examples of moving a component using Key Bindings.
For animation you should be using a Swing Timer to schedule the animation. Check the table of contents from the tutorial links I have already provided. There is a section on How to Use Swing Timers.
I am trying to make a simple animation using ActionListener and KeyListener
that will take in keyboard inputs, namely the arrow keys.
The problem is the program is not compiling with KeyListener. Can someone please
shed some light on why and possibly provide help with a solution.
Thanks!
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Planegame extends JPanel implements ActionListener, KeyListener
{ //^^ this line is giving me trouble^^^^
Timer tim = new Timer(20, this);
int x = 0, y = 0, velX = 0, velY = 0;
public Planegame()
{
tim.start(); //this will start my animation
addKeyListener(this); // will activate the keylistner to watch key press
setFocusable(true);
setFocusTraversalKeysEnabled(false); //disables shift and tab key
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillOval(x, y, 10, 10);
}
public void actionPerformed(ActionEvent e)
{
x = x + 10; //velX
y = y + velY;
repaint();
}
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode()==38)
{
velY = 1;
}
if(e.getKeyCode()==40)
{
velY = -1;
}
if (e.getKeyCode()==32) //booster power
{
velX = 3;
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(keyEvent e) {}
public static void main(String[] args)
{
PlaneGame zed = new PlaneGame();
JFrame k = new JFrame();
k.setTitle("game");
k.setSize(600,400);
k.setVisible(true);
k.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
k.add(zed);
}
}
You have a typo in the declaration of keyReleased method...
public void keyReleased(keyEvent e) {
Remember, Java is case sensitive, it should be...
public void keyReleased(KeyEvent e) {
Note the uppercase K in KeyEvent
You wish to consider using the #Override annotation on methods that you think you are overriding, this will alert you when you've made a mistake of some kind, for example
#Override
public void keyReleased(KeyEvent e) {
There's also no reason why paintComponent should be public, you never want some one outside of your component to call it
As always, I'd advise using key bindings over KeyListener as they provide better control over the level of focus your component needs to be able to trigger a key event
What's the best way I can make random obstacles come my way so my square can dodge them? Kinda like flappy bird but small box like obstacles.
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Jumpy
extends Applet
implements KeyListener{
private Rectangle rect;
public void init()
{
this.addKeyListener(this);
rect = new Rectangle(50, 400, 50, 50);
}
public void paint(Graphics g)
{
setSize(500, 500);
Graphics2D g2 = (Graphics2D)g;
g2.fill(rect);
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP)
{
rect.setLocation(rect.x, rect.y - 13);
}
if (e.getKeyCode() == KeyEvent.VK_DOWN)
{
rect.setLocation(rect.x, rect.y + 13);
}
repaint();
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}}
I don't want you to write my code. I'm just asking what method/way/how would be best to make moving obstacles come my way? I'm new to java so something simple and smooth...Thanks
I am fairly new to Java and LWJGL. I am trying to make a 2d sprite change appearance so it faces in the direction that you are holding, how would I go about this?
So far I have this-
package keyboardinputdb;
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 KeyboardInputDB extends JFrame{
//Variables
int x, y, scoreCount;
private Image dbImage;
private Graphics dbg;
Image littleAdventurer;
boolean faceLeft;
boolean faceRight;
boolean faceUp;
Font font = new Font("Arial", Font.BOLD, 18);
//Action Listener
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT){
x-=3;
if(x <= 0){
x = 0;
}
}
if(keyCode == e.VK_RIGHT){
x+=3;
if(x >= 235){
x = 235;
}
}
if(keyCode == e.VK_UP){
y-=3;
if(y <= 20){
y = 20;
}
}
if(keyCode == e.VK_DOWN){
y+=3;
if(y >= 235){
y = 235;
}
}
}
public void keyReleased(KeyEvent e){
}
}
public KeyboardInputDB(){
//Load Images
ImageIcon i = new ImageIcon("C:/Users/Clive/Documents/NetBeansProjects/KeyboardInput with DB/src/keyboardinputdb/littleAdventurer.gif");
littleAdventurer = i.getImage();
//Game Properties
addKeyListener(new KeyboardInputDB.AL());
setTitle("Java Game");
setSize(600, 500);
setResizable(false);
setVisible(true);
setBackground(Color.black);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x = 150;
y = 150;
scoreCount = 0;
}
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.white);
g.drawString("Score: " + scoreCount, 450, 70);
if(faceLeft = true){
g.drawImage(littleAdventurer, x, y, this);
}
else{
g.setColor(Color.white);
g.fillOval(x, y, 15, 15);
}
repaint();
}
public static void main(String[] args) {
KeyboardInputDB javagame = new KeyboardInputDB();
}
}
Any help with this would be appreciated.
First of all, your main problem is that you're using jFrame instead of LWJGL. I would recommend that you change to LWJGL first. You're also using three boolean variables for which direction your sprite is facing. What happens when both faceLeft and faceRight are true? You should use enums instead.
I assume you're new to Java, so I'll give you a little tutorial in enums...
1st, add this to the top of your class where you declare your varaibles:
public static enum Direction{
UP, DOWN, LEFT, RIGHT
}
public static Direction direction = Direction.DOWN;
You can now use this code to check if an enum is a certain value:
if(direction == Direction.LEFT){
//Do something.
}
You can also set an enum simply by calling:
direction = Direction.RIGHT;
And even easier way to check an enum's vause is by using a switch statement:
switch(direction){
case UP:
//Do something when up.
break;
case DOWN:
//Do something when down.
break;
case LEFT:
//Do something when left.
break;
case RIGHT:
//Do something when right.
break;
}
This best way that I can describe an enum to beginners is similar to a boolean (where it has a limited amount of options) but you can make as many options as you want.
Your current system also isn't using LWJGL, so I recommend changing to that if that's what you would like to use. Making a game is much easier with LWJGL than jFrame once you learn how to use OpenGL.
This page will prove useful: http://lwjgl.org/wiki/index.php?title=Main_Page#Getting_started
Just made quads first, then you can easily learn how to add a sprite in and rotate it using glRotatef()