MouseDragged & MouseMoved not working in Java Applet - java
I'm currently working on a map generation program for a game I'm creating, and so I'm trying to be able to modify the individual tiles on the map using my mouse. I've successfully implemented the ability to click on a tile and change its value (from say a 4 way tile to a 2 way tile), but I am having trouble getting mouseDragged to work. According to the Java docs I've done the correct implementation of the mouseDragged interface into my MouseEventHandler, but I when I drag my mouse and move my mouse around neither of those events trip and throw the println text that I've got them throwing right now. If anyone could shed some light as to why this isn't working for me, I'd love that. Thanks!
A side question: If anyone has any better methods of trying to generate a map like this, or any (presumably anything is better than what I did) other methods of detecting individual mousePressed on a tile, I'd love to hear it. This is only my first time working with this sort of thing so I'm quite inexperienced and would love some advice.
As for the code itself:
File 1: OneQuestMapgen.java
package OneQuestMapgen;
import java.awt.Graphics;
import java.util.ArrayList;
import javax.swing.*;
import tiles.Tile;
import tiles.TileSet;
public class OneQuestMapgen extends JApplet{
/**
*
*/
public static OneQuestMapgen instance;
ArrayList<ArrayList<Tile>> map = new ArrayList<ArrayList<Tile>>();
TileSet tileSet = new TileSet();
public void init(){
this.setSize(950,600);
}
public void start(){
this.addMouseListener(new MouseEventListener(this));
int tileSize = tileSet.get("grasslands")[1].getHeight();
for (int i = 0; i < getHeight(); i += tileSize) {
ArrayList<Tile> temp = new ArrayList<Tile>();
for (int j = 0; j < getWidth(); j += tileSize) {
temp.add(new Tile(j, i, tileSize, tileSet.get("grasslands")));
}
map.add(temp);
}
}
public void paint(Graphics g){
for (int i = 0; i < map.size(); i++){
for(int j = 0; j < map.get(i).size(); j++){
map.get(i).get(j).render(g);
}
}
}
public void stop(){
}
public void destroy(){
}
public ArrayList<ArrayList<Tile>> getMap(){
return map;
}
}
File 2: MouseEventListener.java
package OneQuestMapgen;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import tiles.Tile;
public class MouseEventListener implements MouseListener, MouseMotionListener {
OneQuestMapgen instance;
ArrayList<ArrayList<Tile>> map;
public MouseEventListener(OneQuestMapgen instance) {
this.instance = instance;
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println(e.getX() + " , " + e.getY());
map = instance.getMap();
for (int i = 0; i < map.size(); i++) {
for (int j = 0; j < map.get(i).size(); j++)
if (map.get(i).get(j).bounds(e)) {
map.get(i).get(j).onClicked(instance.getGraphics());
}
}
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseDragged(MouseEvent arg0) {
System.out.println("Mouse Dragged: " + arg0.getX() + " , " + arg0.getY());
}
#Override
public void mouseMoved(MouseEvent arg0) {
// TODO Auto-generated method stub
System.out.println("Mouse Moved: " + arg0.getX() + " , " + arg0.getY());
}
}
File 3: Tile.java
package tiles;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
#SuppressWarnings("serial")
public class Tile extends Square {
BufferedImage[] tiles;
int tileValue = 0;
public Tile (int x, int y, int size, BufferedImage[] tileSet){
super(x,y,size);
tiles = tileSet;
}
public void render(Graphics g) {
g.drawImage(tiles[tileValue], getX(), getY(), getDimension(), getDimension(), null);
}
public void onClicked(Graphics g) {
tileValue++;
System.out.println(tileValue);
g.drawImage(tiles[tileValue], getX(), getY(), getDimension(), getDimension(), null);
}
public boolean bounds(MouseEvent e){
if (e.getX() <= getX() + getDimension() && e.getX() >= getX() && e.getY() <= getY() + getDimension() && e.getY() >= getY())
return true;
return false;
}
}
File 4: TileSet.java
package tiles;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
import javax.imageio.ImageIO;
public final class TileSet {
ConcurrentHashMap<String, BufferedImage[]> container = new ConcurrentHashMap<String, BufferedImage[]>(11);
BufferedImage[] grasslands = new BufferedImage[11];
public TileSet(){
boolean toAdd = true;
try {
grasslands[0] = ImageIO.read(new URL("http://i675.photobucket.com/albums/vv118/va023/OneQuest/GrassBlank_zpse99de845.png"));
grasslands[1] = ImageIO.read(new URL("http://i675.photobucket.com/albums/vv118/va023/OneQuest/4WayTile_zps49ebbeea.png"));
grasslands[2] = ImageIO.read(new URL("http://i675.photobucket.com/albums/vv118/va023/OneQuest/LineHorizontal_zpsc7bd45d5.png"));
grasslands[3] = ImageIO.read(new URL("http://i675.photobucket.com/albums/vv118/va023/OneQuest/LineVertical_zps9719b63f.png"));
grasslands[4] = ImageIO.read(new URL("http://i675.photobucket.com/albums/vv118/va023/OneQuest/TShapeTop_zpsa4b2aaa1.png"))
}
catch (Exception e) {
System.out.println("Unable to load resources for Grasslands");
}
for (int i = 0; i < grasslands.length; i++)
if (grasslands[i].getWidth() != grasslands[i].getHeight()) {
System.out.println("Error, tiles are not square. Grasslands has not been added.");
toAdd = false;
}
if (toAdd) {
container.put("grasslands".toLowerCase(), grasslands);
}
}
public BufferedImage[] get(String s) {
return container.get(s.toLowerCase());
}
}
File 5: Square.java
package tiles;
import javax.swing.JLabel;
public abstract class Square extends JLabel{
/**
*
*/
private static final long serialVersionUID = 1L;
private int x;
private int y;
private int dimension;
public Square(int x, int y, int dimension){
this.x = x;
this.y = y;
this.dimension = dimension;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getDimension(){
return dimension;
}
}
Note: If you would rather be able to pull it all off of github, I've added a link to my github repo for this project below:
URL: https://github.com/vagrawal1/OneQuestMapgen
HTTPS: https://github.com/vagrawal1/OneQuestMapgen.git
SSH: git#github.com:vagrawal1/OneQuestMapgen.git
Git Read-Only: git://github.com/vagrawal1/OneQuestMapgen.git
Thanks once again for your help and thank you for taking the time to read this.
You need to add a MouseMotionListener for dragging to work. You're just adding a MouseListener.
i.e.,
public void start() {
MouseEventListener myMouseEventListener = new MouseEventListener(this);
addMouseListener(myMouseEventListener);
addMouseMotionListener(myMouseEventListener);
//this.addMouseListener(new MouseEventListener(this));
Also as per my comments, your getX() and getY() methods of the Square class override the same methods of JLabel, and that if you aren't careful with these and use them correctly they can totally mess up the placement of your components in the GUI. Myself, I take great pains to avoid overriding these very methods. Consider changing their names if overriding wasn't your intention.
Also, I tend to favor mousePressed(...) over the mouseClicked(...) method as the former will respond to the press even if you move the mouse after pressing it.
Edit: another bug! You should almost never get your Graphics instance by calling getGraphics() on a component as the Graphics object returned is evanescent and may soon become null. Instead either draw on a BufferedImage which is displayed in a JComponent or JPanel's paintComponent(...) or just draw in paintComponent(...) itself.
Edit 2: why override paint(...)? That seems a bit dangerous to me, especially since you're not calling the super method, and especially since there is no need to do this sort of thing.
Related
Make a drawn object move around randomly on a JPanel
This is my frog class which is being called by a GUI class. import java.awt.Color; import java.awt.Graphics; import java.util.Random; import javax.swing.ImageIcon; import javax.swing.JLabel; public class Frog implements Runnable { private int x, y, dx, dy; private int coordinates[]=new int[2]; private boolean hungry; private JLabel jLabel; private ImageIcon image; private String name; public Frog() { } public Frog(String name, boolean hungry) { image = new ImageIcon("images/frog.jpeg"); jLabel = new JLabel(image); setName(name); setHungry(hungry); setCoordinates(); } private void setName(String name) { this.name=name; } public int[] getCoordinates() { return coordinates; } public boolean isHungry() { return hungry; } public void setHungry(boolean hungry) { this.hungry = hungry; } public void display(Graphics paper) { paper.setColor(Color.black); paper.drawOval(x, y, dx, dx); } public void setCoordinates() { for(int i = 0; i < 2; i++) { Random rand = new Random(); int p = rand.nextInt(100); coordinates[i] = p; } setX(coordinates[0]); setY(coordinates[1]); } public void move() { x = (int)Math.random() * 350; y = (int)Math.random() * 350; dx=20; dx=20; x += dx; y += dy; if (x > 800 || x < 0) dx=-dx; if (y > 600 || y < 0) dy=-dy; } public void setDx(int dx) { this.dx = dx; } public void setDy(int dy) { this.dy = dy; } public void setX(int x){ this.x = x; } public void setY(int y){ this.y = y; } public void run() { while(!hungry) { move(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } I have created this class to move a frog object randomly but when I call the move method nothing is happening. I want the frog on a JPanel to randomly move around the screen. I have another class which uses the frog object. It is used from a main class containing the following: public void actionPerformed(ActionEvent event) { if (event.getSource() == MakePet) { String petName = namePlace.getText(); frog = new Frog(petName,false); panel.add(pet); panel.add(prey); frog.move(); Thread fro = new Thread(frog); fro.start(); } } public static void main(String[] args) { GUI demo = new GUI(); demo.setSize(520,720); demo.createGUI(); demo.show(); }
For an example of timer based animation, have a look at http://www.java2s.com/Code/Java/2D-Graphics-GUI/Timerbasedanimation.htm Another example of timer based animation, where Swing components are used to draw images on a JPanel was given Jérôme's comment: Randomly moving images on a JPanel If you require having multiple frogs with their own threads of control, then you will need to handle synchronization. Otherwise I would simply call move from the timer before repainting the panel. And then change move: public void move() { if (!hungry) { return; } ... } Set the timer's interval appropriately based on the framerate you are looking to achieve. The below is based on the answer from the question Jérôme linked to: Timer t = new Timer(1000 / DESIRED_FRAMERATE, (event) -> { frogs.forEach(Frog::move); panel.repaint(); }); Note that this is Java 8 using lambdas. The above in pre-Java 8: Timer t = new Timer(1000 / DESIRED_FRAMERATE, new ActionListener() { public void actionPerformed(ActionEvent event) { for (Frog frog : frogs) { frog.move(); } panel.repaint(); } }); You should create the Timer in the initialization code of your JFrame or JPanel. If you have a class extending JPanel, you don't need to reference panel when calling repaint if the Timer is inside that class. Also, here I am guessing you have a collection of Frog objects, typically a list, called frogs. If there's only ever one frog, you don't need the loop. Frog's display method needs to be called from the JPanel's paint method, so I am guessing you have a class extending JPanel.
Swing 2D game low performance
I am making a clone of Flappy Bird. I was doing just fine performance-wise: 60 fps. This was when it had 1 pillar/obstacle only. As soon as I added 3 of them my fps dropped to 30 and below. Then game is unplayable now. I get that this has something to do with doing repaint() all the time. Here is the code: import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import java.util.ArrayList; /** * Created by Lazar on 25/05/15. */ public class Environment extends JComponent implements ActionListener { public static final Dimension dimension = new Dimension(800,600); BufferedImage img; BufferedImage ptica1; BufferedImage ptica2; double skokbrojac = 0; int brzina = 4; // speed // MUST Background % brzina = 0 int dx; int dx2; int pad = 0; //drop Timer timer; boolean parno; boolean skok = false; //Stubovi // Pillars Stub stub1 = new Stub(); Stub stub2 = new Stub(); Stub stub3 = new Stub(); ArrayList<Stub>stubovi = new ArrayList<Stub>(); int razmakStub; // Space between pillars public Environment() { setPreferredSize(dimension); img = Util.openImage("pozadina.png"); ptica1 = Util.openImage("ptica1.png"); ptica2 = Util.openImage("ptica2.png"); stubovi.add(stub1); stubovi.add(stub2); stubovi.add(stub3); dx = img.getWidth()/2; timer = new Timer(1000/60,this); timer.start(); addMouseListener(new MouseAdapter() { #Override public void mousePressed(MouseEvent e) { super.mousePressed(e); skok = true; // start jump skokbrojac = 0; //jump frame counter } }); } protected void paintComponent(Graphics g){ Graphics2D g2d = (Graphics2D)g; //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); if(dx == img.getWidth()){ //image horizontal scroll dx2 = 0; } if(dx2 == img.getWidth()/2){ //image horizontal scroll dx = dimension.width; } g2d.drawImage(img,getWidth() - dx, 0, null); //draw background if(dx >= img.getWidth()){ g2d.drawImage(img,getWidth() - dx2, 0, null); } if(parno){ g2d.drawImage(ptica1,dimension.width/2, 290 + pad, null); //draw bird } else{ g2d.drawImage(ptica2,dimension.width/2, 290 + pad, null); //draw bird } stub1.postoji = true; //pillar1 exists? if(razmakStub > 240){ stub2.postoji = true; } if(razmakStub > 480){ //pillar1 exists? stub3.postoji = true; } for(Stub i : stubovi){ //draw pillars if they exist if(i.postoji) i.crtaj(g2d); } } #Override public void actionPerformed(ActionEvent e) { dx = dx + brzina; dx2 = dx2 + brzina; if(skokbrojac > 5) // jump frame lenght skok = false; if(skok){ pad -= 15; // jump height } else{ pad += 8; //rate of the fall } skokbrojac++; parno ^= true; // for different bird images if(290 + pad >= 536 || 290 + pad<= 3) //border hit detect timer.stop(); razmakStub += brzina; for(Stub i : stubovi){ //reset pillars and make them move if(i.postoji){ if(i.getDx() < -50){ i.setDx(800); i.randomDy(); } i.setDx(i.getDx() - brzina); } } repaint(); } } Complete project source Also bear in mind this is really unpolished version so the code is ugly. I am looking for a solution to boost performance. Main Class: import javax.swing.*; /** * Created by Lazar on 25/05/15. */ public class Main { public static void main(String[] args){ SwingUtilities.invokeLater(new Runnable() { #Override public void run() { new Frame(new Environment()); } }); } } Frame class: import javax.swing.*; /** * Created by Lazar on 25/05/15. */ public class Frame extends JFrame{ public Frame(JComponent content){ setContentPane(content); setTitle("Flappy"); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(getPreferredSize()); setResizable(false); setVisible(true); setLocationRelativeTo(null); } } Stub/Pillar class: import java.awt.*; import java.awt.image.BufferedImage; import java.util.Random; /** * Created by Lazar on 26/05/15. */ public class Stub { BufferedImage dole; BufferedImage gore; Random r = new Random(); int dx = 700; int dy = r.nextInt(250) + 250; boolean postoji = false; public void crtaj(Graphics2D g2d){ dole = Util.openImage("stub_dole.png"); gore = Util.openImage("stub_gore.png"); g2d.drawImage(dole, dx, dy, null); g2d.drawImage(gore, dx, -(560-dy), null); } public void setDx(int dx) { this.dx = dx; } public void randomDy(){ this.dy = r.nextInt(250) + 250; } public int getDx() { return dx; } } Ptica/Brid class: import java.awt.Graphics; import java.awt.image.BufferedImage; /** * Created by Lazar on 26/05/15. */ public class Ptica { BufferedImage ptica1; BufferedImage ptica2; boolean ptica; boolean skok = false; int pad = 0; double skokBrojac = 0; public Ptica(){ ptica1 = Util.openImage("/slike/ptica1.png"); ptica2 = Util.openImage("/slike/ptica2.png"); } public void crtajPticu(Graphics g2d){ ptica ^= true; if(ptica){ g2d.drawImage(ptica1, Environment.dimension.width/2, Environment.dimension.height/2-110 + pad, null); } else{ g2d.drawImage(ptica2, Environment.dimension.width/2, Environment.dimension.height/2-110 + pad, null); } System.out.println(pad); } public void setSkok(boolean skok) { this.skok = skok; } public void setSkokBrojac(double skokBrojac) { this.skokBrojac = skokBrojac; } public double getSkokBrojac() { return skokBrojac; } public boolean isSkok() { return skok; } public void setPad(int pad) { this.pad = pad; } public int getPad() { return pad; } } Util class: import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.IOException; /** * Created by Lazar on 25/05/15. */ public class Util { public static BufferedImage openImage(String name){ try { if(!name.startsWith("/slike/")){ name="/slike/"+name; } return ImageIO.read(Util.class.getResource(name)); } catch (IOException e) { e.printStackTrace(); } return null; } }
Avoid adding all you classes to the default package, this could cause issues with class loading on some versions of Java Painting should paint the state and should not be making decisions or changing the state Don't, repeatedly, load resources For example, from you Stub class, which Environment's paintComponent calls crtaj, you do the following... public void crtaj(Graphics2D g2d){ dole = Util.openImage("stub_dole.png"); gore = Util.openImage("stub_gore.png"); g2d.drawImage(dole, dx, dy, null); g2d.drawImage(gore, dx, -(560-dy), null); } Loading the images can take time. You should either have a "cache" class which managers them (loading them once) or load them when the Stub class is created (I'd prefer the cache class, as if you create and destroy many Stubs, loading the resources within the Stub class (constructor for example) could become a bottle neck For example, which was able to go from 200-300 objects moving simultaneously, to over 4000 through the use of a re-usable object cache (rather the re-creating the objects and re-loading their resources)
Use a profiler to determine where you code is actually spending time (Note that YourKit has a 15 day free trial license available). Once you know what your bottleneck is then determine if there's an easy fix, if not consider better algorithms and data-structures to reduce the algorithmic complexity of your code.
Profiling, as suggested by #alex-fitzpatrick, is always good. Also: Is the type of images created by your Util.openImage call compliant with the graphics2D object you paint on? You may be spending some with the conversions (image types). eliminate calls to getWidth() etc. You know these values after object initialization, cache them. If possible, don't call repaint on the entire component. Use the overloaded version that specifies the area to repaint. ... and consider using JavaFX for games :-)
Adding a mouseListener/ mouseEvent to each object in an objects list
I am trying to add a mouselistener to each object that is in an objects list. I am rendering a frame as well as multiple objects, using canvas and graphics g. This is my main class: this renders the frame as well as the objects. This all works well and there is no problem here. import java.awt.Canvas; import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferStrategy; public class Proj2 extends Canvas implements Runnable{ private final int[][] Init_board = {{1,0,1,0,1,0,1,0}, {0,1,0,1,0,1,0,1}, {1,0,1,0,1,0,1,0}, {0,1,0,1,0,1,0,1}, {1,0,1,0,1,0,1,0}, {0,1,0,1,0,1,0,1}, {1,0,1,0,1,0,1,0}, {0,1,0,1,0,1,0,1}}; private final int[][] new_Game = {{5,5,5,5,5,5,5,5}, {5,5,5,5,5,5,5,5}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}, {4,4,4,4,4,4,4,4}, {4,4,4,4,4,4,4,4}}; public static final int WIDTH = 640; public static final int HEIGHT = 640; private final int initPieces = 8; private Thread thread; private boolean running = false; private Board board; private GameHandler handler; public Proj2(){ handler = new GameHandler(); new Window(WIDTH,HEIGHT,"Checkers",this); board = new Board(WIDTH,HEIGHT,Init_board); for(int i = 0; i < 8; i++){ for(int j = 0; j < 8; j++){ handler.newObject(new Player(j * (640 / initPieces),i * (640 / initPieces),initPieces,ID.playerOne,new_Game[i][j],handler)); } } This is where I'm not sure if I am doing it right. I have created the objects above, and render them to the frame. Then I try to add a mouslistener to each object so that they can each have their own MouseEvent. This is still in my main class. for(int i = 0; i < handler.gameObjects.size(); i++){ GameObjects temp = handler.gameObjects.get(i); this.addMouseListener(new MouseInput(temp)); } } The rest renders the frame and starts the game loop. This is my handler class. This class creates an objects list, and adds and removes objects when required. import java.awt.Graphics; import java.util.LinkedList; public class GameHandler { LinkedList<GameObjects> gameObjects = new LinkedList<GameObjects>(); public void tick(){ for(int i = 0; i < gameObjects.size(); i++){ GameObjects temp = gameObjects.get(i); temp.tick(); } } public void render(Graphics g){ for(int i = 0; i < gameObjects.size(); i++){ GameObjects temp = gameObjects.get(i); temp.render(g); } } public void newObject(GameObjects object){ this.gameObjects.add(object); } public void deleteObject(GameObjects object){ this.gameObjects.remove(object); } } This is the MouseInput class: Where each object is sent to and has a MouseEvent. What I want here is that each object should have a different MouseEvent ID, so when it is clicked on it returns a unique ID for each object. However at this moment it returns the same value for all objects. I want to be able to select and object, by clicking on it, and then click on a new position and that object should move there. import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.LinkedList; public class MouseInput implements MouseListener { private GameHandler handler; private GameObjects object; public MouseInput(GameObjects Object){ this.object = Object; } #Override public void mouseClicked(MouseEvent arg0) { } #Override public void mouseEntered(MouseEvent e) { } #Override public void mouseExited(MouseEvent arg0) { } #Override public void mousePressed(MouseEvent e) { int x = e.getX(); int y = e.getY(); int b = e.getClickCount(); int c = e.getID(); /*NOT SURE WHAT TO DO HERE*/ /*THIS JUST MOVES THE OBJECT WHERE I CLICK, BUT WHEN I HAVE MULTIPLE OBJECTS AND I CLICK, ONLY ONE OBJECT MOVES AND THE REST DISAPEAR*/ if(b == 2){ if(object.getID() == ID.playerOne ){ object.setX(x); object.setY(y); } } } #Override public void mouseReleased(MouseEvent arg0) { // TODO Auto-generated method stub } } Apologies for all the code. I tried to post as little as possible.
I try to add a mouslistener to each object so that they can each have their own MouseEvent. for(int i = 0; i < handler.gameObjects.size(); i++) { GameObjects temp = handler.gameObjects.get(i); this.addMouseListener(new MouseInput(temp)); } That code is adding the MouseListener to the same object, not a different object. Instead I would guess the code should be: //this.addMouseListener(new MouseInput(temp)); temp.addMouseListener(new MouseInput(temp)); so when it is clicked on it returns a unique ID for each object. If you want to know which object was clicked you can get that information from the MouseEvent: GameObjects temp = (GameObjects)e.getSource();
My picture is moving too slowly
I am currently making a kind of adventure 2D game project for university. I have drawn an array of pictures(walls,floor etc) and then the movable hero figure. The problem: without the array the figure is moving fine but with the array the movement starts to lag hard. Is it my Pc? or is my drawing method too "heavy"? Please take a look: import java.awt.Graphics; import java.awt.Rectangle; public class World { public static int WorldW = 16 , WorldH = 16; public SpielElement[][] element = new SpielElement[WorldW][WorldH]; public int[][] level0 ={{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0}, {0,0,0,1,1,1,1,1,1,1,1,6,0,0,0,0}, {0,0,0,1,1,1,5,1,1,1,1,1,0,0,0,0}, {0,0,0,1,1,6,1,1,2,1,5,1,0,0,0,0}, {0,0,0,1,1,1,1,5,1,1,1,1,0,0,0,0}, {0,0,0,1,1,1,0,0,0,1,1,1,0,0,0,0}, {0,0,0,0,0,1,1,3,1,1,0,0,0,0,0,0}, {0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; public int[][] level1 ={{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,1,0,0,0,0,1,1,1,1,2,0,1,0}, {0,4,0,1,0,0,5,1,1,1,1,1,1,0,1,0}, {0,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0}, {0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0}, {0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0}, {0,1,1,1,0,0,1,1,1,1,1,0,0,1,0,0}, {0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0}, {0,1,0,1,1,1,1,1,1,1,1,1,0,0,3,0}, {0,1,0,1,0,0,0,0,0,1,0,1,0,0,1,0}, {0,1,0,1,1,1,1,0,0,1,0,1,0,0,1,0}, {0,1,0,1,0,0,1,0,0,1,0,1,1,1,1,0}, {0,1,0,0,0,0,1,0,0,1,0,0,1,0,0,0}, {0,1,1,1,1,6,1,1,0,1,0,0,1,0,0,0}, {0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; public World(){ create(); } public void create(){ for(int x = 0; x<WorldW; x++){ for(int y = 0; y<WorldH; y++){ element[x][y] = new SpielElement(x,y,level0[y][x]); } } } public void generate(Graphics g){ for(int x = 0; x<WorldW; x++){ for(int y = 0; y<WorldH; y++){ element[x][y].zeichne(g); } } } } Well the int array is to define which kind of picture I need to draw and i intend to first create all the Panels (SpielElement) and then draw them Here is how i Draw them: import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.*; public class SpielElement extends JPanel{ int posX,posY,type ; BufferedImage wand, boden, tuer, schluessel; public SpielElement(int x, int y,int z){ this.posX = x*40; this.posY = y*40; this.type = z; try { wand = ImageIO.read(SpielElement.class.getResource("/img/wand.png")); boden = ImageIO.read(SpielElement.class.getResource("/img/boden.png")); tuer = ImageIO.read(SpielElement.class.getResource("/img/tuer.png")); schluessel = ImageIO.read(SpielElement.class.getResource("/img/schluessel.png")); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void zeichne(Graphics g){ switch(type){ case 0: g.drawImage(wand,posX,posY,boden.getWidth(),wand.getHeight(),null); break; case 1:g.drawImage(boden,posX,posY,boden.getWidth(),boden.getHeight(),null); break; case 2: g.drawImage(schluessel,posX,posY,schluessel.getWidth(),schluessel.getHeight(),null); break; case 3: g.drawImage(tuer,posX,posY,tuer.getWidth(),tuer.getHeight(),null); break; case 4: g.drawImage(boden,posX,posY,boden.getWidth(),boden.getHeight(),null); break; case 5:g.drawImage(boden,posX,posY,boden.getWidth(),boden.getHeight(),null); break; case 6: g.drawImage(boden,posX,posY,boden.getWidth(),boden.getHeight(),null); break; } } } I hope u get what I am thinking by reading the code and hopefully see what is wrong. There are no Syntax errors whatsoever but its so damn slow. In the end added all of this onto a JPanel Board which is added on a JFrame import java.awt.*; import javax.swing.*; import java.awt.event.*; public class Board extends JPanel implements KeyListener{ private final int BREITE = 700; private final int HOEHE = 700; Hunter Held ; World Welt; public Board(){ super(); Held = new Hunter(200,200); Welt = new World(); this.setBackground(Color.BLACK); } public void paint(Graphics g){ super.paint(g); Welt.generate(g); Held.draw(g); } #Override public void keyPressed(KeyEvent e) { // TODO Auto-generated method stub if (e.getKeyCode() == KeyEvent.VK_LEFT) Held.posX = Held.posX - 10; if (e.getKeyCode() == KeyEvent.VK_RIGHT) Held.posX = Held.posX + 10; if (e.getKeyCode() == KeyEvent.VK_UP) Held.posY = Held.posY - 10; if (e.getKeyCode() == KeyEvent.VK_DOWN) Held.posY = Held.posY + 10; this.repaint(); } #Override public void keyReleased(KeyEvent arg0) { // TODO Auto-generated method stub } #Override public void keyTyped(KeyEvent arg0) { // TODO Auto-generated method stub } } the Hero(Held) is drawn the exact way like the other images with its Coordinates beeing altered everytime i press keys and thus repainted. I will refrain from further code dumping at this point. This is how it looks like in the end: http://puush.me/account?pool=1468274 (Sorry no reputation yet) The figure on Scrren moves on KeyInput but with lags... This is my first question and i hope it is detailed enough. Sry in advance if my problem is stupid only started 2 weeks ago with programming in general. Constructive critizism is adviced. sry for code Dumping...
Until I saw you mentioned JPanel and JFrame, I thought it was an Android related question... Anyway maybe you should draw them in a new thread, on an invisible canvas/image/cache, whatever... then bring it to front and draw another frame in background. Sorry, I don't know how to do it with Swing, but I think that's how all animation frameworks work. In Android people do all these dirty work in background thread...
GUI Making Arrays of Images that Move Using Mouse Event
I am pretty overwhelmed at the moment with this assignment. I am only 3 weeks into Java programming and I was given this code and told to modify it in ways I'm not exactly familiar with. So any help would be greatly appreciated. I really want to understand this, so any information would also be helpful. The directions that I'm struggling with at the moment are: "Modify the Model class to store an ArrayList of Turtles. Make Model.update call Turtle.update for each Turtle in the ArrayList. To test it, put two or three turtles in the ArrayList, each starting in different locations. When you click (which causes "setDestination" to be called), make all of the turtles head for the same destination. Get this much working before you proceed." Before I created an array of these turtles, one turtle showed up fine. Now that I have created an array, nothing is showing up on my panel. It does compile properly, though. I understand that I should make separate Graphics objects, but how and where would be the best place to do this? Here is the code (which was in 4 separate files): Controller.java import java.awt.Graphics; import java.io.IOException; import java.awt.event.MouseListener; import java.awt.event.MouseEvent; import javax.swing.Timer; class Controller implements MouseListener { Model model; View view; Controller() throws IOException, Exception { model = new Model(); view = new View(this); new Timer(50, view).start(); } public void update(Graphics g) { model.update(g); } public void mousePressed(MouseEvent e) { model.setDestination(e.getX(), e.getY(), view.getWidth(), view.getHeight()); } public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } public static void main(String[] args) throws Exception { // Use the following line to determine which directory your program // is being executed from, since that is where the image files will // need to be. //System.out.println("cwd=" + System.getProperty("user.dir")); new Controller(); } } Model.java import java.awt.Graphics; import java.io.IOException; class Model { private Turtle[] t; Model() throws IOException { Turtle[] t = new Turtle[3]; for (int i = 0; i <3; i++) t[i] = new Turtle(); // turtle = new Turtle(); } public void update(Graphics g) { for(int i = 0; i <3; i++) t[i].update(g); } public void setDestination(int x, int y, int width, int height) { for(int i = 0; i <3; i++) { t[i].setDest(x, y); } } } Turtle.java import java.awt.Graphics; import java.awt.Image; import javax.imageio.ImageIO; import java.io.File; import java.io.IOException; import java.util.Random; class Turtle { private int x; private int y; private int dest_x; private int dest_y; private Image image; Turtle() { try { image = ImageIO.read(new File("turtle.png")); } catch (IOException ioe) { System.out.println("Unable to load image file."); } } public int getX() { return x; } public int getY() { return y; } public void setX(int xIn) { x = xIn; } public void setY(int yIn) { y = yIn; } public void update(Graphics g) { // Move the turtle if (x < dest_x) { x += 1; } else if (x > dest_x) { x -= 1; } if (y < dest_y) { y += 1; } else if (y > dest_y) { y -= 1; } // Draw the turtle } public void setDest(int x, int y) { dest_x = x; dest_y = y; } } View.java import javax.swing.JFrame; import java.awt.Graphics; import javax.swing.JPanel; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; public class View extends JFrame implements ActionListener { private class MyPanel extends JPanel { Controller controller; MyPanel(Controller c) { controller = c; addMouseListener(c); } public void paintComponent(Graphics g) { controller.update(g); revalidate(); } } public View(Controller c) throws Exception{ setTitle("Assignment 4"); setSize(1000, 700); getContentPane().add(new MyPanel(c)); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public void actionPerformed(ActionEvent evt) { repaint(); } }
I'm positively surprised by the code supplied by the teacher; usually it's pretty bad, but this one is decent. Although you need to modify only one class, allow me to comment a bit more because "any information would also be helpful". Controller class Controller extends MouseAdapter instead of class Controller implements MouseListener allows you to get rid of all the empty methods public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } (And in case you need to extend controller with something else just make an inner class extending MouseAdapter and use that.) Turtle Should expose a constructor such as Turtle(int x, int y) { this(); this.x = x; this.y = y; } so that Turtle t = new Turtle(); t.setX(4); t.setY(6); could be replaced with new Turtle(4, 6); Furthermore, dest_x and dest_y should be renamed to something like destX and destY since underscore (_) is used only in names of final instances. Lastly, you need to replace the line // Draw the turtle with g.drawImage(image, x, y, null); View The dimensions specified in setSize(1000, 700); should be defined as fields (don't scatter arbitrary numbers across the code) int sizeX = 1000, sizeY = 700; ... setSize(sizeX, sizeY); and should be exposed so that when choosing initial location for the turtles they won't start out of bounds. Model You were asked: Modify the Model class to store an ArrayList of Turtles, but you created an array instead for some reason. Here is an example of what you can do to make it work: public class Model { private List<Turtle> turtList = new ArrayList<>(); private int turtleNumber = 3; Model() throws IOException { for (int i = 0; i < turtleNumber; i++) { Turtle turt = new Turtle(); turt.setX(Math.round((float)Math.random() * 1000)); turt.setY(Math.round((float)Math.random() * 700)); turtList.add(turt); } } public void update(Graphics g) { for (int i = 0; i < turtleNumber; i++) turtList.get(i).update(g); } public void setDestination(int x, int y, int width, int height) { for (Turtle turt : turtList) turt.setDest(x, y); } } I define the number of turtles I want as a field and use it throughout the code so I need to change it only in one place when I change the number. In the constructor, I loop using the given turtle constructor (a null constructor) and randomly place them inside the frame's bounds (they should be read from View's sizeX and sizeY). Then I add the modified turtle to the list. For instructional purpose, I used two different looping constructs for update and for setDestination. Choose whichever you want (just notice that you don't need to know the number of turtles).
In the constructor of your Model class you have the line Turtle[] t = new Turtle[3]; You also have the class variable, Turtle[] t but are not assigning the array initialised in the Constructor to the class variable, so it is only considered for the scope of that method and hence why nothing is drawn, as when you go to use the variable t later it has not been initialised and so you get NullPointerExceptions To fix this simply change the line Turtle[] t = new Turtle[3]; to t = new Turtle[3]; Now this will only appear as one image, but is actually 3 turtles overlaid on top of each other. So to fix this you will need some extra code to put the turtles in different starting positions, but i'll leave you to figure this part out.