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()
Related
I have been following some java game development tutorial , and I was able to create an oval shaped object that can move with my keyboard input and created boundaries , however I attempted to replace the oval with an image but for some reason it is not showing up, I'm pretty sure the image I chose is not large , it is more like a small icon and thanks in advance.
package javagame;
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 JavaGame extends JFrame{
int x,y;
private Graphics dbg;
private Image dbImage;
Font font = new Font("Arial" , Font.BOLD, 30);
Image face;
public class AL extends KeyAdapter{
public void keyPressed(KeyEvent e){
int KeyCode = e.getKeyCode();
if(KeyCode == e.VK_LEFT) {
if(x<=0)
x=0;
else
x -=15;
}
if(KeyCode == e.VK_DOWN) {
if(y>=480)
y=480;
else
y+=5;
}
if(KeyCode == e.VK_UP) {
if(y<=20)
y=20;
else
y-=5;
}
if(KeyCode == e.VK_RIGHT) {
if(x>=480)
x=480;
else
x+=5;
}
}
public void keyReleased(KeyEvent e){
}
}
public JavaGame() {
//game images
ImageIcon i = new ImageIcon("C:/Users/Sheref/Documents/NetBeansProjects/avaGame/src/javagame/type-of-solder-001-512.gif");
face = i.getImage();
//game properties
addKeyListener(new AL());
setTitle(" Strategy Game");
setSize(500,500);
setResizable(true);
setVisible(true);
setBackground(Color.CYAN);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x = 20 ;
y = 30;
}
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.drawImage(face, x, y, this);
repaint();
}
public static void main(String[] args) {
new JavaGame();
}
}
In your paint method, instead of
this.dbImage = this.createImage(this.getWidth(), this.getHeight());
put:
this.dbImage = this.createImage((int) this.getSize().getWidth(), (int) this.getSize().getHeight());
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.
So I am trying to make a snake game for my final project in my programming class. I am trying to add to the snake using an array, since using an array of objects is one of the requirements for the project. But I can't figure out how to make it work. Can anyone tell me what I am doing wrong?
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class FinalApplet extends Applet implements KeyListener {
private Image grass;
private Image mouse;
private Snake[] mySnake = new Snake[100];
private int x;
private int y;
public void init() {
grass = getImage(getCodeBase(), "grass.jpg");
mouse = getImage(getCodeBase(), "mouse.png");
addKeyListener(this);
}
public void update (Graphics g) {
paint(g);
}
public void paint(Graphics g) {
Image buffer = createImage(getWidth(), getHeight());
Graphics z = buffer.getGraphics();
z.drawImage(grass, 0, 0, this);
z.drawImage(mouse, 200, 130, this);
z.setColor(Color.RED);
z.fillRect(x, y, 20, 20);
g.drawImage(buffer, 0, 0, this);
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
y = y + 1;
repaint();
}
else if (e.getKeyCode() == KeyEvent.VK_UP) {
y = y - 1;
repaint();
}
else if(e.getKeyCode() == KeyEvent.VK_LEFT){
x = x - 1;
repaint();
}
else if (e.getKeyCode() == KeyEvent.VK_RIGHT){
x = x + 1;
repaint();
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
I suppose your snake starts with at least a length of 1, for it to be shown. That means that your array in its first element has a starting coordinate. All other cells of the array are empty (or null whichever you are using) and hence should not be painted on your canvas, i.e. should not be shown to your user.
A solution could be that every time your snake moves, you update each cell of your array (taking into account that each cell is a section of your snake) with its new position.
When the snake overlaps with the position of a "mouse" then the next available cell on your array should have the last position of your last (now before last) cell, taking into account that it should not move until its previous cell has moved and that only cells that have an actual value should be painted.
I hope this helps, but you should try and post more code so we could help with specific programming problems.
Im working on an assignment where an image moves around and when the user clicks on the image it will change and as soon as it moves again via timer class, the images chages back to the original. As of now I can click the image to change it, but it wont change back when it is time to move again. Is there a way to change back after it moves?
Here is my code
Main:
import java.awt.*;
import javax.swing.*;
public class Catch_The_Creature
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Catch the Creature");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JOptionPane.showMessageDialog(frame, "Catch Pikachu!");
frame.getContentPane().add(new Creature());
frame.pack();
frame.setVisible(true);
}
}
Panel:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Creature extends JPanel
{
private static final int DELAY=900;
private Random generator = new Random();
private ImageIcon image, image1;
private Timer timer;
private int x, y;
private int catchCount=0;
public Creature()
{
image = new ImageIcon ("pikachu.png");
image1 = new ImageIcon ("pokeball.png");
timer = new Timer(DELAY, new MoveListener());
x = generator.nextInt( 1900 );
y = generator.nextInt(1000);
addMouseListener (new MouseClickedListener());
setBackground (Color.green);
setPreferredSize(new Dimension(1900,1000));
timer.start();
}
//Draws the image.
public void paintComponent(Graphics page)
{
super.paintComponent(page);
image.paintIcon (this, page, x, y);
page.drawString("Pikachus Captured: " + catchCount, 10, 35);
setFont(new Font("Arial", Font.BOLD,35));
}
//Method for moving the image.
public void move()
{
timer.start();
x = generator.nextInt( 1900 );
y = generator.nextInt(1000);
if (timer.isRunning())
{
x = generator.nextInt( 1900 );
y = generator.nextInt(1000);
}
repaint();
}
//Method for getting the number of times caught.
public int getCatchCount()
{
return catchCount;
}
//Makes the image move
private class MoveListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
move();
repaint();
}
}
//Records when the user clicks the image.
private class MouseClickedListener extends MouseAdapter
{
public void mouseClicked(MouseEvent event)
{
if((event.getButton() == MouseEvent.BUTTON1) && between(event.getX(), x, x + image.getIconWidth()) && between(event.getY(), y, y + image.getIconHeight()))
{
System.out.println("CAUGHT ONE!");
catchCount++;
move();
image=image1;
}
}
}
private static boolean between(int x, int lower, int upper)
{
return (x >= lower) && (x <= upper);
}
}
i hope i understand what do you try to achieve. first you need 3 Images:
private ImageIcon imageToDraw, image1, image2;
Creature will look like this now:
public Creature()
{
image1 = new ImageIcon ("pikachu.png");
image2 = new ImageIcon ("pokeball.png");
imageToDraw = image1;
...
}
in move() you should set the image to image1:
public void move()
{
imageToDraw = image1;
timer.start();
x = generator.nextInt( 1900 );
...
}
dont forget to change image to imageToDraw in paint():
public void paintComponent(Graphics page)
{
super.paintComponent(page);
imageToDraw.paintIcon (this, page, x, y);
...
}
remove move(); from onclick-event and change image to imageToDrwa in click-action:
public void mouseClicked(MouseEvent event)
{
if((event.getButton() == MouseEvent.BUTTON1) && between(event.getX(), x, x + image.getIconWidth()) && between(event.getY(), y, y + image.getIconHeight()))
{
System.out.println("CAUGHT ONE!");
catchCount++;
//move(); should be removed
imageToDraw=image1;
}
}
edit:move(); removed from onclick-event
You need a way to paint either Image. Right now you are just assigning image to image1 and when you do that the Image that is from "pikachu.png" disappears.
Without restructuring too much you can just make a flag for which one to paint:
/* as a field */
private boolean justCaptured;
Now you have to change your painting logic a little:
if (justCaptured) {
image1.paintIcon (this, page, x, y);
} else {
image.paintIcon (this, page, x, y);
}
Now the first thing you do is instead of reassigning image, set the flag to true:
System.out.println("CAUGHT ONE!");
catchCount++;
justCaptured = true;
move();
There's one last thing you need to do which is to set the flag back to false for the next draw. There are some different ways to approach this but the simplest I see without refactoring a number of things is to queue it for later:
System.out.println("CAUGHT ONE!");
catchCount++;
justCaptured = true;
move();
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
justCaptured = false;
}
});
Using invokeLater will enqueue it at the end of EventQueue and it will be changed after previously queued tasks complete. So after the mouse event exits and then after the repaint you've just requested in move.
"I post all of it in case anyone would like to give advice on other things general things."
You're calling timer.start in move and this doesn't appear necessary. Timers repeat by default.
move generates x and y twice. Since you call timer.start in the constructor, timer.isRunning will always be true.
MoveListener calls repaint after calling move but move also calls repaint.
"Also so people can test it themselves if they would like to."
We can't run it because we don't have your images. If you want to post it so we can run it change the code so it works without them. Otherwise we have to go and change it somehow ourselves. Here's a static method that returns a blank ImageIcon:
public static ImageIcon createBlankIcon(int w, int h, Color color) {
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(color);
g2d.fillRect(0, 0, w, h);
g2d.dispose();
return new ImageIcon(img);
}
You can substitute something like that for content, eg: image = getBlankIcon(50, 50, Color.RED);.
I am simply trying make a game for college that is a ball that player navigates with keyboard to get through maze. The only thing I am stuck on is my background is an image of a maze, when I add the "ball" it repaints the background (defualt color, no image) when I comment out the paint and paint component, the maze background is back, but no ball of course.
I am a new to java and I have searched this and can't see a good soulition for the code I already have. is it setOpaque? isOpaque?.... is opaque even the right direction?
Once I get this... i totally understand using collision detection to detect collisions with the maze "wall"
Trying to figure this out, being new to java, can make a grown man cry.
main.java
public class Main{
public static void main (String[] args){
//System.out.println("Start of the Game");
GameFrame game1 = new GameFrame();
}
JavaGame.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import java.io.File;
import java.io.IOException;
public class GameFrame extends JFrame{
private int frameWidth = 240, frameHeight =315;
int x, y;
private Image dbImage;
private Graphics dbg;
//Below is the constructor
public GameFrame(){
super("OperationMaze!");
addKeyListener(new AL());
setResizable(false);
//setTitle("OperationMaze!2");
//setSize(250, 302);
setSize(frameWidth, frameHeight); //Set height and width
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Because of opening file, there needs to be a try catch just incase there is an error opening.
//Plus java won't let you unless you try catch.
try{
setContentPane(new JLabel(new ImageIcon(ImageIO.read(new File("C:/Documents and Settings/brando/My Documents/NetBeansProjects/GameFrame/src/maze.jpg")))));
} catch (IOException e) {
e.printStackTrace();
}
//Show the frame
setVisible(true);
//setOpaque(false);
y = 35;
x = 15;
}
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.fillOval(x, y, 15, 15);
//g.setOpaque(false);
repaint();
}
// private void setOpaque(boolean b) {
// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
// }
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT) {
if(x <= 5)
x = 5;
else
x += -5;
}
if(keyCode == e.VK_RIGHT) {
if(x >= 230)
x = 230;
else
x += +5;
}
if(keyCode == e.VK_UP) {
if(y <= 23)
y=23;
else
y += -5;
}
if(keyCode == e.VK_DOWN) {
if(y >= 277)
y = 277;
else
y += +5;
}
}
}
}
Ok, lets's see what's going wrong here:
when I add the "ball" it repaints the background (default color, no image)
In this scenario, when you are using your custom paint method, you don't call super.paint(g), so the JLabel with the Image doesnt get drawn.
The Image that you do create is blank:
dbImage = createImage(getWidth(), getHeight());
(Graphics offers a convenient overloaded method of drawImage that allows you to specify width & height, allowing you to avoid doing this.)
The result: no background image.
when I comment out the paint and paint component, the maze background is back, but no ball of course.
Now Swing is calling the default paint implementation which ensures that all child components are drawn but now you're not calling your fillOval method, net result: background Image, no ball.
Where next:
To allow Swing do the work of custom painting you need to override paintComponent rather than calling it directly. However this cannot be done in a top level container like JFrame. Sub-classing a JComponent and overriding paintComponent in that new component will allow Swing to call that method without you having to do it directly. Adding the #Override will allow the compiler to check that you are indeed overriding the method. As you're intending to paint the Image, you could simply load the Image and save the reference for use when you need to paint it:
dbImage = ImageIO.read(new File("MyImage.jpg"));
Then in your new JComponent-based class:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(dbImage, 0, 0, getWidth(), getHeight(), this);
g.fillOval(x, y, 15, 15);
}