simple intro java game programming - java

My question is where did i go wrong. it is supposed to make a frame where i can control an oval, move it around back forth left and right, and then make it move with the arrows. but right now i cant even make the oval, or even insert a word into it.
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
public class JavaGame extends JFrame{
int x, y;
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode ==e.VK_LEFT){
x--;
}
if(keyCode ==e.VK_RIGHT){
x++;
}
if(keyCode ==e.VK_DOWN){
y--;
}
if(keyCode==e.VK_UP){
y++;
}
}
public void keyReleased(KeyEvent e){
}
}
public JavaGame (){
addKeyListener(new AL());
setTitle("Game");
setSize(250,250);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void Paint(Graphics g){
x = 150;
y = 150;
g.fillOval(x, y, 15, 15);
repaint();
}
public static void main(String[] Args){
new JavaGame();
}
}

Probably because Paint isn't a standard Java paint method. I don't see anything resembling an event loop, either--have you considered checking out any Swing tutorials/etc.?

Recommendations:
As Dave says, you need to override the correct method
even so, you shouldn't be drawing directly in a top-level window but rather in a component that derives from JComponent such as JPanel or JComponent itself.
draw in this class's paintComponent(...) method (usually).
Use the #Override annotation to make sure that you are truly overriding a class's method.
Don't use KeyListener's with Swing but rather Key Bindings.
For example, please have a look at my sample code here: How to make an image move while listening to a keypress in Java.

Related

How to get keyEvent to work in Java?

I'm completely new at programming Java. I can't get my keyEvents to wont work. I need this for a little game I'm making. Here is my code:
package markusrytter.pingpong;
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;
public class main extends JPanel implements KeyListener {
static int ballX;
static int ballY;
static int ballR = 15;
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(ballX - ballR, ballY - ballR, ballR * 2, ballR * 2);
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Sample Frame");
main game = new main();
frame.add(game);
frame.setSize(1400, 800);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
ballX = frame.getContentPane().getSize().width / 2;
ballY = frame.getContentPane().getSize().height / 2;
while (true) {
game.repaint();
Thread.sleep(10);
}
}
public void keyPressed(KeyEvent e) {
System.out.println("A key is Pressed: " + e.getKeyCode());
if(e.getKeyCode() == KeyEvent.VK_SPACE){
System.out.println("Spacebutton pressed");
}
}
}
I do hope someone can help, I have tried to watch videos but again, I'm new at java.
Your code won't compile since you didn't implement KeyListener (completely)
You didn't add the key listener to the panel in its constructor.
KeyEvents are only dispatched to components with focus. Your panel is not focusable so it will never receive events. You use the method setFocusable(true).
Don't override paint(). Instead you should be overriding paintComponent(...).
You shouldn't even be using a KeyListener. Instead when using Swing you should be using Key Bindings.
Don't use static variables for the properties of your class.
Your GUI is not created on the Event Dispatch Thread (EDT).
i have read articles, i have watched videos, and done everything exactly like them,
Obviously not or it would work.
For a proper tutorial start with the Swing Tutorial. There are sections on:
How to Write a KeyListener
Custom Painting
Key Bindings.
Concurrency
Most importantly: change the name of your class. It's called main and that's a bad idea. Also it's much more advisable to override paintComponent() instead of paint.
You didn't add the keylistener to the JFrame. You should call this in your main after creating game:
frame.addKeyListener(game);
You also need to add the remaining KeyListener methods.
and that should do it.

Java animation freeze

I am trying to write a simple 2d animation engine in Java for visualizing later programming projects. However, I am having problems with the window refresh. On running, the frame will sometimes display a blank panel instead of the desired image. This begins with a few frames at a time at apparently random intervals, worsening as the program continues to run until the actual image only occasionally blinks into view. The code for processing each frame is run, but nothing in the frame is actually displayed. I believe the problem may come from my computer more than my code (certainly not from bad specs though), but am not sure. Help much appreciated.
Three classes. Code here:
package animator;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.applet.AudioClip;
public class APanel extends JPanel
{
public APanel(int l, int h){
setPreferredSize(new Dimension(l,h));
setLocation(80, 80);
setVisible(true);
setFocusable(true);
}
public Graphics renderFrame(Graphics g){
return g;
}
public void paintComponent(Graphics g) {
requestFocusInWindow();
renderFrame(g);
}
}
package animator;
import java.awt.*;
public class Animator extends APanel
//extending the APanel class allows you to code for different animations
//while leaving the basic functional animator untouched
{
public static final int SCREEN_X = 700;
public static final int SCREEN_Y = 700;
int frameNum;
public Animator() {
super(SCREEN_X, SCREEN_Y);
frameNum = 0;
}
public Graphics renderFrame(Graphics g) {
frameNum++;
g.drawString(""+frameNum,5,12);
return g;
}
}
package animator;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.Timer;
public class Runner {
int framerate = 30;
Animator a = new Animator();
JFrame j = new JFrame();
public Runner(){
j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
j.add(a);
start();
j.setSize(a.getPreferredSize());
j.setVisible(true);
}
public void start() {
Timer t = new Timer(1000/framerate, new ActionListener() {
public void actionPerformed(ActionEvent e){
j.getComponent(0).paint(j.getComponent(0).getGraphics());
//The following line of code keeps the window locked to a preferred size
// j.setSize(j.getComponent(0).getPreferredSize());
}
});
t.start();
}
public static void main(String[] args){
Runner r = new Runner();
}
}
There are some serious mistakes in your code which could be the cause or a factor of your problem...
j.setSize(a.getPreferredSize()); is irrelevant, simply use JFrame#pack, you get better results as it takes into account the frame decorations
j.setSize(j.getComponent(0).getPreferredSize()); use JFrame#setResizable and pass it false instead...
NEVER do j.getComponent(0).paint(j.getComponent(0).getGraphics()); this! You are not responsible for the painting of components within Swing, that's the decision of the RepaintManager. Just call j.repaint()
super(SCREEN_X, SCREEN_Y);...just override the getPreferredSize method and return the size you want.
setLocation(80, 80); irrelevant, as the component is under the control of a layout manager
setVisible(true); (inside APanel)...Swing components are already visible by default, with the exception of windows and JInternalFrames
And finally...
public void paintComponent(Graphics g) {
requestFocusInWindow();
renderFrame(g);
}
There is never any need for this method to be made public, you NEVER want someone to be able to call it, this will break the paint chain and could have serious ramifications in the ability for the component to paint itself properly.
You MUST call super.paintComponent before performing any custom painting, otherwise you could end up with all sorts of wonderful paint artifacts and issues
Never modify the state of a component from within a paint method...while it "might" not be an immediate issue calling requestFocusInWindow(); within your paintComponent could have side effects you don't know about...
Instead, it should look more like...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
renderFrame(g);
}

Resizing only way to repaint JFrame . repaint(); seems to not work

Im currently trying to make my first game and i am having trouble getting the repaint() method to work. I have checked my keyListeners and have confirmed that they are working a ok! The ship that i have created moves but only if i forcibly resize the window by dragging on the sides. If anyone has any tips i would be very greatful!
If you need any more information feel free to ask!
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Main extends Canvas implements KeyListener{
public static Ship playerShip = new Ship(150,450,"F5S4-Recovered.png");
public int numberOfEnemies = 0;
public static void createFrame(){
Window frame1 = new Window();
final JPanel pane = new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(0, 0, 1000, 1000);
g.drawImage(playerShip.image, playerShip.xPos1, playerShip.yPos1, this);
}
};
frame1.add(pane);
}
public void keyTyped(KeyEvent e){System.out.println("KeyTyped");}
public void keyPressed(KeyEvent e){
switch(e.getKeyCode())
{
case KeyEvent.VK_LEFT :
playerShip.xPos1-=2;
break;
case KeyEvent.VK_RIGHT:
playerShip.xPos1+=2;
break;
}
repaint();
}
public void keyReleased(KeyEvent e){}
public static void main(String args[]){
createFrame();
}
}
Window class ----------------------------------------------------------
import javax.swing.*;
public class Window extends JFrame{
public Window()
{
setTitle("Space Game");
setSize(800,800);
setDefaultCloseOperation(EXIT_ON_CLOSE);
addKeyListener(new Main());
setVisible(true);
}
}
Your call to repaint() is repainting the class Canvas, but the painting is done on the JPanel pane. The resizing causes an automatic repaint of the panel. So to fix you want to pane.repaint(), but you can't do that unless you put the panel as a class member, so you can access it from the listener method. Right now, it's currently locally scoped in the createFrame() method.
Also, you should probably add the listener to the panel instead, and not even extend Canvas, since you're not even using it
Other Notes:
Look into using Key Bindings instead of low-level KeyListener
Swing apps should be run from the Event Dispatch Thread (EDT). You can do so by simply wrapping the code in your main in a SwingUtilities.invokeLate(..). See more at Initial Threads
Again, I'll just add, Don't extends Canvas

create game loop thread

Hi I have just been messing about polygons and awt. I have created a Jframe and can draw the polygons ok and have one of them move with keypresses.
I'm wondering how to start a gameloop thread(and where to put it!) that will update the jframe independently.
From googling im led to believe that I should have one thread for user input and one for the game itself.
At the moment I have implemented KeyListener on the board class(code shown below),should I put that out into its own class and make it implement runnable?As the code stands I repaint the JFrame in the keypressed() method just so i can see that it moves correctly
Being at it most of the day and I have myself very very confused :)
As always any help much appreciated!
Also while im at it from online tutourials should I use JPanel instead of JFrame and paintComponent() instead of paint()?
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.AffineTransform;
import javax.swing.JFrame;
public class Board extends JFrame implements KeyListener{
AffineTransform identity = new AffineTransform();
Graphics2D g2d;
Ship ship = new Ship();
public static final int ALIENS = 3;
Alien[] alien = new Alien[ALIENS];
Board(){
super("The Board");
setSize(1280,1024);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setBackground(Color.BLACK);
for(int x=0;x<ALIENS;x++){
alien[x]=new Alien();
}
}
public void paint(Graphics g){
super.paint(g);
addKeyListener(this);
//draw ship
g2d = (Graphics2D)g;
g2d.setTransform(identity);
g2d.translate(ship.getxPos(),ship.getyPos());
g2d.scale(2,2);
g2d.setColor(Color.ORANGE);
g2d.fill(ship.getShape());
g2d.setColor(Color.BLACK);
g2d.draw(ship.getShape());
// draw aliens
for(int x=0;x<ALIENS;x++){
//if alien alive
if(alien[x].isAlive()){
//draw alien
g2d = (Graphics2D)g;
g2d.setTransform(identity);
g2d.translate(alien[x].getxPos(),alien[x].getyPos());
g2d.scale(2,2);
g2d.setColor(Color.BLUE);
g2d.fill(alien[x].getShape());
g2d.setColor(Color.BLACK);
g2d.draw(alien[x].getShape());
}
}
}//end paint
/*****************************************************
* key listener events
*****************************************************/
public void keyReleased(KeyEvent k) { }
public void keyTyped(KeyEvent k) { }
public void keyPressed(KeyEvent k) {
int keyCode = k.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_A:
//move ship left
if(ship.getxPos()<20){
ship.setxPos(20);
}else
ship.setxPos(ship.getxPos()-1);
break;
case KeyEvent.VK_D:
if(ship.getxPos()>1260){
ship.setxPos(1260);
}else
ship.setxPos(ship.getxPos()+1);
}
repaint();
}//end keypressed event
public static void main(String[] args){
new Board();
}
}
These answers depend somewhat on what kind of game you're trying to create.
From googling I'm led to believe that I should have one thread for user input and one for the game itself.
You create one main game loop, which runs in its own thread. In psudeocode
while (running) {
update game model
draw game
wait x milliseconds
}
Your user input would update the game model directly. The game loop updates the game model if the computer is required to make moves or react to your moves. Then, the game loop reads the game model and draws the game based on the values in the model.
At the moment I have implemented KeyListener on the board class(code shown below),should I put that out into its own class and make it implement runnable?
Yes, you should put KeyListener into its own class. No, you don't have to make it a separate thread.
To save yourself future trouble, your Swing components should be defined and used on the Event Dispatch thread.
Here's how you do that.
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Board();
}
});
}
Should I use JPanel instead of JFrame and paintComponent() instead of paint()?
Yes.
You should have a JPanel inside of a JFrame. The JPanel is where you perform the draw game psudeocode, using the paintComponent method.
Some people are going to disagree with me, but I've found it best if every object in the game has a draw method to draw itself.
public void draw(Graphics g)
The game model would also have a draw method, which draws all of the objects in the model.
The JPanel paintComponent method would look like this:
public void paintComponent(Graphics g) {
super.paintComponent(g);
gameModel.draw(g);
}

JPanels don't appear in the JFame

I'm new to java. I do have a java class but I want to get ahead. I really like it! This is my problem. I'm trying to draw the two paddles needed for the game. I did create 2 objects for them, and they both "Show" but the following happens:
Main Runner
import javax.swing.JFrame;
public class PongRunner {
public static void main (String[] args)
{
new PongRunner();
}
public PongRunner()
{
JFrame PongFrame= new JFrame();
PongFrame.setSize(800,600);
PongFrame.add(new PaddleB());
PongFrame.add(new PaddleA());
PongFrame.setLocationRelativeTo(null);
PongFrame.setTitle("My Pong Game");
PongFrame.setResizable(false);
PongFrame.setVisible(true);
PongFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
PaddleA and PaddleB are both drawRect Graphics and draw a specific rectangle.
The graphics that I tell JFrame to add first are the only ones visible. The one under it doesnt get added into the Frame I wanted to know why,and how i can draw both paddles in the same JFrame... I'm reading my book and looking over the internet as much as possible, but no luck within these 2 days. Some help would be nice. I just started learning java and I think I'm making progress. Some tips would be nice too thanks :), specialy on actionListener since im going to have to use them to move the paddles!
SOURCE CODE OF BOTH PADDLES:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class PaddleA extends JPanel implements ActionListener
{
private Timer timer;
public void timer()
{
timer = new Timer(25, this);
timer.start();
}
public void actionPerformed(ActionEvent e)
{
repaint();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(70,200,20,100);
}
}
PaddleB:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class PaddleB extends JPanel implements ActionListener
{
private Timer timer;
public void timer()
{
timer = new Timer(25, this);
timer.start();
}
public void actionPerformed(ActionEvent e)
{
repaint();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(500, 200, 20, 100);
}
}
As you've added the 2 paddles into the same BorderLayout.CENTER location of the main PongFrame, only the second paddle will be displayed.
This type of painting is more easily done using one Graphics object on one JComponent.
Swing components aren't really designed to be used like this. Each of your paddle JPanels is trying to paint a rectangle, but the container (the JFrame) and its layout manager will control the size and location of the JPanels. So the rectangle they paint may be outside their bounds, and won't appear at all.
Some Layout Managers will only show one of the JPanels if you add them one after another like this - see answer by Reimus.
To do animated graphics like this, you probably need to start with a single JComponent (e.g. a JPanel) that fills the JFrame, and paint both paddles as rectangles onto it.
This is because you add the first paddle and then add the second paddle over the first thus replacing them:
PongFrame.add(new PaddleB());
PongFrame.add(new PaddleA());
try using LayoutManagers here is just a quick sample:
PongFrame.getContentPane().add(new PaddleB(),BorderLayout.WEST);
PongFrame.getContentPane().add(new PaddleA(),BorderLayout.EAST);
also your g.fillRect(...); has x and y co-ordinates that are too large for the JFrame and thus are not displayed. Change it like so:
g.fillRect(0,0, 20, 100);
Not related though:
dont use JFrame.add() rather JFrame.getContentPane().add()
UPADTE:
As others have mentioned the logic for the game is a bit off. You should have a single drawing panel which is added to the JFrame and all drawing is done on the single JPanel using Graphics and not JPanels. Here is a small example:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PongRunner {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new PongRunner();
}
});
}
public PongRunner() {
JFrame PongFrame = new JFrame();
PongFrame.setTitle("My Pong Game");
PongFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
PongFrame.setResizable(false);
PongFrame.setSize(400,400);
//PongFrame.setLocationRelativeTo(null);
PongFrame.getContentPane().add(new DrawingPanel());
PongFrame.setVisible(true);
}
}
class DrawingPanel extends JPanel {
Rect rect1, rect2;
public DrawingPanel() {
super(true);
rect1 = new Rect(80, 80, 20, 100, Color.yellow);
rect2 = new Rect(100, 200, 20, 100, Color.red);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(rect1.getColor());
g.fillRect(rect1.getX(), rect1.getY(), rect1.getWidth(), rect1.getHeight());
g.setColor(rect2.getColor());
g.fillRect(rect2.getX(), rect2.getY(), rect2.getWidth(), rect2.getHeight());
}
}
class Rect {
private Color color;
private int x, y, height, width;
Rect(int x, int y, int width, int height, Color color) {
this.x = x;
this.y = y;
this.height = height;
this.width = width;
this.color = color;
}
public Color getColor() {
return color;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
}
Please note this snippet is not perfect and merely demonstrates the stereotypical logic needed for drawing rectangles to form a game of sorts
I don't have time to try running your code, but try setting the size and position of the "paddle" objects, or set them as non-opaque. I believe that Swing tries to speed up rendering by not drawing components which are completely covered by another opaque component. It may not be drawing one of your paddles for that reason.
If you do set the size and position of your paddles, you may have to modify your paintComponent methods: if my memory is correct, I think the Graphics object which is passed in is clipped to the area of the component, so 0,0 would be the top-left corner of the component.
you shouldn't add your JPanels to your JFrame by the JFrame#add(Component) method. Better add them to the contentPane: frame.getContentPane().add(panel); You should although read about LayoutManagers. They can help you by positining Components in your Frame or mess things up if you use them incorrect.

Categories

Resources