📜 ⬆️ ⬇️

Writing a 2-d game in Java # 2

Good day to all! Continuation of the 1st lesson ( link to the first ).

Tasks


Today we have to create a player and implement the movement method in it.

Start


Let's get started First, create a new class Player.java.

Create several variables of type int. The first is x, the second is y, and the third is speed. Let them be private, in order to avoid further errors (set them immediately, x = 0, y = 0, speed = any speed, I will set 2). Also, create three methods - getSpeed ​​(), getX () and getY (). They look like this:
')
public int getX() { return x; } public int getY() { return y; } public int getSpeed() { return speed; } 

They will return us the current x and y coordinates of our player, as well as the player’s speed.

Now, we need a method responsible for the movement. So we call it - move. As long as we do not have a key listener, for this, we simply write:

  public void move() { x+= speed; } 

We return to our class Main.java and in it, create the object of our player:

 Player player = new Player(); 

Further, in the actionPerformed () method we write:

 player.move(); 

Now, with each update of the timer, the player will move. But now we will not see this movement, because We do not use player coordinates. Now I will briefly explain how the movement occurs on the screen. It’s not the picture of our player that moves, but the background, which simulates the player’s movement. So, go to the paint () method and, instead of drawing coordinates, enter player.getX () and player.getY (). It should go like this:

 g.drawImage(img, player.getX(), player.getY(),frame.getWidth(), frame.getHeight(), null); 

Run, and see that our background is moving.

Now I will explain what we did not quite correctly.

We must have two separate coordinates - the coordinate of the map and the coordinate of the player. What is it for? Now we are drawing a layer relative to the player's coordinates. In the future, we will have objects located on the map, and it will be easier for the player to interact with them, having map coordinates. I hope, explained clearly, and now we will realize it.

In a good way, we must have a separate object, the Universe (Universe), which will contain information about our map (time of day, coordinates, etc.). In the subsequent lessons we will do this, but for now, we simply add two new variables in the player’s class: mapX and mapY, and immediately set their values, 0 and 0. And, as in the case of x and y, we will create 2 getters.

Now we will correct our method move ().

Let's write instead of x + = speed this:

 x-=speed; mapX+=speed; 

And back to the paint method and change

 g.drawImage(img, player.getX(), player.getY(),frame.getWidth(), frame.getHeight(), null); 

On:

 g.drawImage(img, player.getMapX(), player.getMapY(),frame.getWidth(), frame.getHeight(), null); 

We start, and see that nothing has changed. This is a good sign, so we did everything right.

But we see that the picture is one, and behind it remains a trace. And here we come to such a fork. We can create a game in which the world will constantly expand, depending on which direction the player is heading. Or, to make a game with a certain size location, beyond which it is impossible to go, but the location can change. What problems I encountered when creating these two options. If we create a game without limits, then:

  1. It will be necessary to carry out the generation of this world, and if it has no limits, then it must be made random, i.e. There will be drawing bugs that we will encounter all the time.

If you will create a game based on a change of locations, then:

  1. Either it will be straightforward, with a plot, or a change of locations will be random, but in this case, problem number 2 arises.
  2. There should be a lot of locations so that a person does not get tired of playing this game.

Under this article is a survey. Do not forget to vote.

Well, while we manage without additional layers, we will create a listener of keystrokes.

In the constructor of the class Main.java, we add the following line:

 frame.addKeyListener(new KeyAdapter() { }); 

Some may ask why we use the “add listener” method and add an adapter? The adapter simply allows us not to use all three methods of the class of the listener, but let's say, as in our case, we implement only two in it:

 @Override public void keyPressed(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub } 

The first method is responsible for pressing the key, and the second for releasing it. The third method responds to a short keystroke, rather than delaying it, as in the first method. Now, so that we do not get a beleberd, and in order not to complicate our lives, we will do exactly the same two methods in the player’s class. And now in our methods that are in the class Main.java we write:

In keyPressed:

 player.keyPressed(e); 

In keyReleased:

 player.keyReleased(e); 

Done! Now we have a keystroke listener. Let's check its performance by simply writing the following line in each of the methods in the Player.java class:

 System.out.println(e.getKeyCode()); 

Run the program, look at our console, and click on the keys.

If each time you press a key, numbers are written out to the console, this means that you did everything correctly. Do not be afraid, it is not necessary to memorize all these keys, the KeyEvent class has already done this for us.

Now create an enum that will be responsible for the direction of the player. For those who do not know, enum, this is a variable that can have several values ​​that we have previously registered. Create an enum called Direction. In it, separated by commas, we write the following values: UP, DOWN, LEFT, RIGHT, NONE. Now, in the Player class, create a new variable of type Direction, which we will call playerDirection (immediately set the value to Direction.NONE). Now, we will make it so that when you press the corresponding buttons, the player's direction changes. By the way, we will always work with the keyPressed and keyReleased methods from the Player.java class; in the Main.java class, do not touch them. So, for starters, in the keyPressed method, we declare a variable, of type int, which is equal to e.getKeyCode (). We do this for convenience, so that in the future each time not to prescribe the same thing. So, then we write:

 if(key == KeyEvent.VK_W) { playerDirection = Direction.UP; } if(key == KeyEvent.VK_S) { playerDirection = Direction.DOWN; } if(key == KeyEvent.VK_A) { playerDirection = Direction.LEFT; } if(key == KeyEvent.VK_D) { playerDirection = Direction.RIGHT; } 

These are conditions, how our direction of the player will change depending on the keys pressed.

Next, change the move method. It should look like this:

 switch(playerDirection) { case UP: mapY+=speed; break; case DOWN: mapY-=speed; break; case LEFT: mapX+=speed; break; case RIGHT: mapX-=speed; break; default: break; } 

For those who do not know, switch is the same as if, only in a more convenient form. Run the program, and admire!

That's all for today. Again, I leave all the code for those who get confused.

Player.java


 import java.awt.event.KeyEvent; public class Player { private int x = 0; private int y = 0; private int speed = 2; private int mapX = 0; private int mapY = 0; private Direction playerDirection = Direction.NONE; public void move() { switch(playerDirection) { case UP: mapY+=speed; break; case DOWN: mapY-=speed; break; case LEFT: mapX+=speed; break; case RIGHT: mapX-=speed; break; default: break; } } public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if(key == KeyEvent.VK_W) { playerDirection = Direction.UP; } if(key == KeyEvent.VK_S) { playerDirection = Direction.DOWN; } if(key == KeyEvent.VK_A) { playerDirection = Direction.LEFT; } if(key == KeyEvent.VK_D) { playerDirection = Direction.RIGHT; } } public void keyReleased(KeyEvent e) { System.out.println(e.getKeyCode()); } public int getX() { return x; } public int getY() { return y; } public int getSpeed() { return speed; } public int getMapX() { return mapX; } public int getMapY() { return mapY; } } 

Main.java


 import java.awt.Graphics; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; public class Main extends JPanel implements ActionListener { Image img = new ImageIcon("2.png").getImage(); Timer timer = new Timer(20, this); Player player = new Player(); JFrame frame; public Main(JFrame frame) { this.frame = frame; timer.start(); frame.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { // TODO Auto-generated method stub player.keyPressed(e); } @Override public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub player.keyReleased(e); } }); } public void paint(Graphics g) { g.drawImage(img, player.getMapX(), player.getMapY(),frame.getWidth(), frame.getHeight(), null); } @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub repaint(); player.move(); } } 

Display.java


Has not changed.

Thanks for attention! Do not forget to vote.

Source: https://habr.com/ru/post/326302/


All Articles