Witam Serdecznie
Od pewnego czasu staram się zrobić grę w Javie. Jest to moje pierwsze zetknięcie z tym językiem (programuję od jakiegoś miesiąca).
Do tej pory szło mi całkiem nieźle - zrobiłem menu, parsowanie plików, odczytywanie mapy, jednak przyszedł moment, gdy nie za bardzo mi wychodzi i mam problemy. Jednym z nich jest sterowanie postacią. Nie wiem, jak się za to zabrać, a animacja musi być płynna oraz musi następować kolizja ze ścianami w planszy gry. Udało mi się tylko "wprowadzić" postać gracza na planszę, jednak dalsza potyczka ze sterowaniem mnie przerosła.
Jeśli chodzi o szczegóły - sterowanie ma się odbywać za pomocą strzałek. Na postać mają działać siły fizyczne - najważniejsze to grawitacja. Postać ma poruszać się w każdą stronę, nawet w górę (nie skakać!).
Drugą sprawą jest skalowanie gry - w moim przypadku mapy oraz postaci - jest to druga rzecz, na której poległem.
Czy mógłby mi ktoś z tym pomóc?
W tym momencie mój kod składa się z 11 klas i wyglądają tak (w załączniku dodałem plik konfiguracyjny oraz plik z mapą):
Klasa Game:
package game;
import java.awt.Dimension;
import java.io.IOException;
import javax.swing.JFrame;
/**
* Klasa wywołująca główne okno gry
*
*/
public class Game extends JFrame{
public static void main(String[] args) throws IOException{
JFrame frame = new JFrame("Ball Revamped");
Configuration conf = new Configuration();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setMinimumSize(new Dimension(conf.minimum_width, conf.minimum_height));
frame.add(new MainMenu());
frame.pack();
frame.setVisible(true);
}
}
Klasa GameFrame
package game;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import javax.swing.JPanel;
/**
* Tworzenie okna gry
*/
public class GameFrame extends JPanel{
private GameBar game_bar;
//private Map map;
private TileMap map;
Configuration conf = new Configuration();
private Player player;
/**
* Tworzy elementy planszy oraz przyciski.
*
* @param parent Sprawia, że ten panel jest w stanie wywołać metody jego rodzica.
* @throws IOException
*/
public GameFrame(MainMenu parent) throws IOException{
setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.insets = new Insets(0,400,0,0);
map = new TileMap("Map.txt", 32);
player = new Player(map);
game_bar=new GameBar(parent);
constraints.gridx = 0;
constraints.gridy = 0;
constraints.weighty = 1;
constraints.anchor = GridBagConstraints.PAGE_START;
add(game_bar, constraints);
}
public Dimension getPreferredSize() {
return new Dimension(getParent().getSize());
}
/**
* Klasa rysująca mapę gry z pliku .txt
*
*b - tło gry
*w - ściana
*/
private void update(){
player.update();
}
public void paint(Graphics g) {
super.paint(g);
map.draw(g);
game_bar.repaint();
player.draw(g);
}
/*public void keyTyped(KeyEvent key){}
public void keyPressed(KeyEvent key){
int code = key.getKeyCode();
if(code == KeyEvent.VK_LEFT){
player.setLeft(true);
}
if(code == KeyEvent.VK_RIGHT){
player.setRight(true);
}
if(code == KeyEvent.VK_UP){
player.setJumping(true);
}
}
public void keyReleased(KeyEvent key){
int code = key.getKeyCode();
if(code == KeyEvent.VK_LEFT){
player.setLeft(false);
}
if(code == KeyEvent.VK_RIGHT){
player.setRight(false);
}
}*/
}
Klasa GameBar
package game;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.Timer;
/**
* Tworzy pasek zawierający: czas gry, ilość żyć gracza, punktację oraz
* zawierający przycisk pauzy oraz powrotu do menu
*
*/
public class GameBar extends JPanel{
/**
* Wygląd oraz działanie przycisków
*
* @param parent Makes this panel able to call its parent's methods.
* @throws IOException
*/
public GameBar(MainMenu parent) throws IOException{
setBackground(new Color(31, 31, 31));
BufferedImage menu = ImageIO.read(new File("res/menu.png"));
JButton menu_button = new JButton();
menu_button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0){
parent.goToMenu();
}
});
menu_button.setIcon(new ImageIcon(menu));
menu_button.setPreferredSize(new Dimension(25,25));
menu_button.setMargin(new Insets(1, 1, 1, 1));
menu_button.setBorderPainted(false);
menu_button.setBackground(new Color(31, 31, 31));
menu_button.setFocusPainted(false);
add(menu_button);
}
}
Klasa Configuration
package game;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* Klasa czytająca i prasująca dane z pliku konfiguracyjnego
*
*/
public class Configuration {
public int button_width=0;
public int button_height=0;
public int _width=0, _height=0;
public int minimum_width=0, minimum_height=0;
public int logo_x=0, logo_y=0;
public Configuration(){
FileData config2 = null;
try {
config2 = new FileData("config.txt");
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
try {
this._width = Integer.parseInt(config2.getSetting("PREFERRED WINDOW WIDTH"));
this._height = Integer.parseInt(config2.getSetting("PREFERRED WINDOW HEIGHT"));
this.minimum_width = Integer.parseInt(config2.getSetting("MINIMUM WINDOW WIDTH"));
this.minimum_height = Integer.parseInt(config2.getSetting("MINIMUM WINDOW HEIGHT"));
this.button_width = Integer.parseInt(config2.getSetting("BUTTON WIDTH"));
this.button_height = Integer.parseInt(config2.getSetting("BUTTON HEIGHT"));
this.logo_x = Integer.parseInt(config2.getSetting("LOGO X"));
this.logo_y = Integer.parseInt(config2.getSetting("LOGO Y"));
} catch (NumberFormatException | IOException e) {
e.printStackTrace();
}
}
}
Klasa FileData
package game;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* Klasa czytająca pliki tekstowe używane w grze
*
*/
public class FileData {
private String data_file_name;
/**
* Podaj nazwę pliku tekstowego
*
* @param file_name Nazwa pliku tekstowego
* @throws FileNotFoundException
*/
public FileData(String file_name) throws FileNotFoundException{
data_file_name = file_name;
}
/**
* Policz wszystkie linie w pliku tekstowym
*
* @return Liczbę linii w tekście
* @throws IOException
*/
public int countLines() throws IOException{
FileReader file_reader = new FileReader(data_file_name);
BufferedReader buffered_reader = new BufferedReader(file_reader);
@SuppressWarnings("unused")
String line;
int count=0;
while((line = buffered_reader.readLine()) != null) {
count++;
}
buffered_reader.close();
return count;
}
/**
* Odczytanie całego pliku tekstowego
*
* @return All lines in a string array
* @throws IOException
*/
public String[] readWholeFile() throws IOException {
FileReader file_reader = new FileReader(data_file_name);
BufferedReader buffered_reader = new BufferedReader(file_reader);
int number_of_lines = countLines();
String[] text_data = new String[number_of_lines];
for(int i=0; i<number_of_lines; i++){
text_data[i] = buffered_reader.readLine();
}
buffered_reader.close();
return text_data;
}
/**
* Dodaje linię tekstu podanego w parametrze do pliku
*
* @param line
* @throws IOException
*/
public void addToFile(String line) throws IOException{
FileWriter file_writer = new FileWriter(data_file_name);
BufferedWriter buffered_writer = new BufferedWriter(file_writer);
buffered_writer.write(line);
buffered_writer.newLine();
buffered_writer.close();
}
/**
* Szuka w tekście podanego parametru
*
* @param line
* @return Liczba linii, w których został znaleziony parametr bądź -1 jeśli nie znalazł
* @throws IOException
*/
public int findInFile(String line) throws IOException {
FileReader file_reader = new FileReader(data_file_name);
BufferedReader buffered_reader = new BufferedReader(file_reader);
int count = 0;
String loaded_line;
while((loaded_line = buffered_reader.readLine()) != null) {
count++;
if(loaded_line.equals(line)){
buffered_reader.close();
return count;
}
}
buffered_reader.close();
return -1;
}
/**
* Odczytanie jednej linii
*
* @param line Liczba linii do odczytania.
* @return Odczytanie linii bądź zwrócenie 'null' jeśli parametr jest niezgodny
* lub większy niż liczba linii
* @throws IOException
*/
public String readOneLine(int line) throws IOException {
FileReader file_reader = new FileReader(data_file_name);
BufferedReader buffered_reader = new BufferedReader(file_reader);
int count = 0;
String loaded_line;
while((loaded_line = buffered_reader.readLine()) != null) {
count++;
if(count==line){
buffered_reader.close();
return loaded_line;
}
}
buffered_reader.close();
return null;
}
/**
* Dodanie nowej opcji podczas czytania pliku konfiguracyjnego
*
* @param name Nazwa opcji.
* @param option Wartość opcji.
* @throws IOException
*/
public void addSetting(String name, String option) throws IOException{
addToFile("#"+name);
addToFile(option);
}
/**
* Pobieranie danych z pliku konfiguracyjnego.
*
* @param name Nazwa danej.
* @return Nazwa danej.
* @throws IOException
*/
public String getSetting(String name) throws IOException {
return readOneLine(findInFile("#"+name)+1);
}
}
Klasa InstructionPanel
package game;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.io.IOException;
import javax.swing.JPanel;
/**
* Tworzy okno instrukcji gry
*
*/
public class InstructionPanel extends JPanel{
private GameBar game_bar;
/**
* Tworzy elementy planszy oraz przyciski.
*
* @param parent Sprawia, że ten panel jest w stanie wywołać metody jego rodzica.
* @throws IOException
*/
public InstructionPanel(MainMenu parent) throws IOException{
setLayout(new GridBagLayout());
GridBagConstraints _constraints = new GridBagConstraints();
_constraints.insets = new Insets(0,0,0,0); //top padding
game_bar=new GameBar(parent);
_constraints.gridx = 0;
_constraints.gridy = 0;
_constraints.weighty = 1;
_constraints.anchor = GridBagConstraints.PAGE_START;
add(game_bar, _constraints);
}
public Dimension getPreferredSize() {
return new Dimension(getParent().getSize());
}
public void paint(Graphics g) {
game_bar.repaint();
}
}
Klasa MainMenu
package game;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
/**
*
* Tworzy główne menu gry oraz przechowuje wszystkie panele
* (w tym okno gry)
*
*/
public class MainMenu extends Container{
private int pattern_copied_x=0, pattern_copied_y=0;
private int background_width, background_height;
private BufferedImage background;
private MenuLogo logo;
private MenuPanel menu;
private GameFrame game_frame = new GameFrame(this);
private InstructionPanel instr_panel = new InstructionPanel(this);
Configuration conf = new Configuration();
/**
* Tworzenie wyglądu menu, wczytywanie z pliku
* tła gry a także tworzy niewidoczne okno gry
*
* @throws IOException
*/
public MainMenu() throws IOException{
setLayout(new GridBagLayout());
try
{
background = ImageIO.read(new File("res/tlo.png"));
}
catch (IOException e)
{
e.printStackTrace();
}
background_width=background.getWidth();
background_height=background.getHeight();
Dimension window_size = new Dimension(conf._width, conf._height);
setPreferredSize(window_size);
game_frame.setVisible(false);
createMenu();
}
/**
* Tworzenie loga i panelu menu
*
* @throws IOException
*/
public void createMenu() throws IOException {
GridBagConstraints constraints = new GridBagConstraints();
constraints.insets = new Insets(10,10,10,10);
logo = new MenuLogo();
constraints.gridx = 0;
constraints.gridy = 0;
constraints.weighty = 1;
constraints.anchor = GridBagConstraints.PAGE_START;
add(logo, constraints);
menu = new MenuPanel(this);
constraints.gridx = 0;
constraints.gridy = 5;
constraints.weighty = 1;
add(menu, constraints);
}
public void paint(Graphics g) {
background_width=background.getWidth();
background_height=background.getHeight();
Dimension size = getSize();
pattern_copied_x=size.width/background_width+1;
pattern_copied_y=size.height/background_height+1;
//powielenie tła gry
for(int x=0; x<pattern_copied_x; x++){
for(int y=0; y<pattern_copied_y; y++){
g.drawImage(background, x*background_width,y*background_height, null);
}
}
super.paint(g);
}
/**
* Ukrycie okna menu gry i uwidocznienie okna gry
*/
public void hideMenuGame() {
add(game_frame);
logo.setVisible(false);
menu.setVisible(false);
instr_panel.setVisible(false);
game_frame.setVisible(true);
repaint();
}
/**
* Ukrycie okna menu gry i uwidocznienie okna instrukcji
*/
public void hideMenuInstr() {
add(instr_panel);
logo.setVisible(false);
menu.setVisible(false);
game_frame.setVisible(false);
instr_panel.setVisible(true);
repaint();
}
/**
* Ukrycie okna gry oraz okna instrukcji i powrót do menu
* (uwidocznienie okna menu).
*/
public void goToMenu() {
game_frame.setVisible(false);
instr_panel.setVisible(false);
logo.setVisible(true);
menu.setVisible(true);
repaint();
}
}
Klasa MenuLogo
package game;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
/**
*
*
* Sprawia, że elementem z załadowanego obrazu 'logo'
* mają być wyświetlane w menu.
*
*/
public class MenuLogo extends Component{
private BufferedImage logo;
Configuration conf = new Configuration();
public int logo_x_rozmiar=0, logo_y_rozmiar=0;
public MenuLogo() throws IOException{
logo = ImageIO.read(new File("res/logo.png"));
setPreferredSize(new Dimension(logo.getWidth(),logo.getHeight()));
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(logo.getScaledInstance(logo.getWidth(), logo.getHeight(), Image.SCALE_FAST), conf.logo_x, conf.logo_y, this);
}
public void paint(Graphics g){
g.drawImage(logo, conf.logo_x,conf.logo_y,getWidth(),getHeight(),this);
}
}
Klasa MenuPanel
package game;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JPanel;
/**
* Tworzenie panelu przechowującego wszystki przyciski menu
*/
public class MenuPanel extends JPanel{
Configuration conf = new Configuration();
/**
* Dodanie przycisków pcji menu oraz zainicjowanie ich działania
*
* @param parent Sprawia, że ten panel jest w stanie wywołać metody jego rodzica.
* @throws IOException
*/
public MenuPanel(MainMenu parent) throws IOException {
JButton new_game=new JButton("NOWA GRA");
JButton instructions=new JButton("INSTRUKCJA");
JButton creators=new JButton("TWÓRCY");
JButton exit=new JButton("ZAKOŃCZ");
new_game.setPreferredSize(new Dimension(conf.button_width,conf.button_height));
new_game.setBorderPainted(false);
new_game.setBackground(new Color(59, 115, 201));
new_game.setForeground(new Color(0, 0, 0));
new_game.setFocusPainted(false);
new_game.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0){
parent.hideMenuGame();
}
});
instructions.setPreferredSize(new Dimension(conf.button_width,conf.button_height));
instructions.setBorderPainted(false);
instructions.setBackground(new Color(59, 115, 201));
instructions.setForeground(new Color(0, 0, 0));
instructions.setFocusPainted(false);
instructions.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0){
parent.hideMenuInstr();
}
});
creators.setPreferredSize(new Dimension(conf.button_width,conf.button_height));
creators.setBorderPainted(false);
creators.setBackground(new Color(59, 115, 201));
creators.setForeground(new Color(0, 0, 0));
creators.setFocusPainted(false);
exit.setPreferredSize(new Dimension(conf.button_width,conf.button_height));
exit.setBorderPainted(false);
exit.setBackground(new Color(59, 115, 201));
exit.setForeground(new Color(0, 0, 0));
exit.setFocusPainted(false);
exit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0){
System.exit(0);
}
});
GridLayout layout = new GridLayout(4,1);
layout.setVgap(15);;
setLayout(layout);
setOpaque(false);
add(new_game);
add(instructions);
add(creators);
add(exit);
}
}
Klasa Player
package game;
import java.awt.*;
public class Player {
private double x;
private double y;
private double dx;
private double dy;
private int width;
private int height;
private double moveSpeed;
private double maxSpeed;
private double maxFallingSpeed;
private double stopSpeed;
private double jumpStart;
private double gravity;
private TileMap map;
public Player(TileMap map){
map = map;
width = 40;
height = 40;
moveSpeed = 0.6;
maxSpeed = 4.2;
maxFallingSpeed = 12;
stopSpeed = 0.30;
jumpStart = -11.0;
gravity = 0.64;
}
public void update(){
}
public void draw(Graphics g){
g.setColor(Color.RED);
g.fillOval((int) (17 + x - width/2), (int) (17 + y - height/2), width, height);
}
}
Klasa TileMap
package game;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.io.BufferedReader;
import java.io.FileReader;
import javax.swing.JPanel;
public class TileMap extends JPanel{
public int x;
public int y;
private int tileSize;
private int[][] map;
private int mapWidth;
private int mapHeight;
Configuration conf = new Configuration();
public TileMap(String s, int tileSize){
this.tileSize = tileSize;
try{
BufferedReader br = new BufferedReader(new FileReader(s));
mapWidth = Integer.parseInt(br.readLine());
mapHeight = Integer.parseInt(br.readLine());
map = new int[mapHeight][mapWidth];
String delimiters = " ";
for(int row = 0; row <mapHeight; row++){
String line = br.readLine();
String[] tokens = line.split(delimiters);
for(int col = 0; col <mapHeight; col++){
map[row][col] = Integer.parseInt(tokens[col]);
}
}
}
catch(Exception e){
}
}
public void update(){
}
public void draw(Graphics g){
for(int row = 0; row <mapHeight; row++){
for(int col = 0; col <mapHeight; col++){
int rc = map[row][col];
if(rc == 0){
g.setColor(Color.BLACK);
}
if(rc == 1){
g.setColor(Color.BLUE);
}
g.fillRect(x + col*tileSize, y + row*tileSize, tileSize, tileSize);
}
}
}
}
- config.txt (0 KB) - ściągnięć: 147
- Map.txt (1 KB) - ściągnięć: 136