게임만들기(3) - "JAVADOT" 플랫폼게임
2021. 7. 12. 00:42ㆍ프로그래밍/개인프로젝트
JavaUI를 이용해서 플랫폼게임을 만드는 과정을 기록합니다.
전체코드
package JAVADOT_pkg;
import java.util.ArrayList;
import java.util.HashMap;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class JAVADOT_ver5 extends Application {
private HashMap<KeyCode, Boolean> keys = new HashMap<KeyCode, Boolean>();
private ArrayList<Node> blocks = new ArrayList<Node>();
private ArrayList<Node> energys = new ArrayList<Node>();
private ArrayList<Node> doors = new ArrayList<Node>();
private Pane mainContainer = new Pane();
private Pane blockContainer = new Pane();
private Node player;
private int levelWidth;
private Point2D playerVelocity = new Point2D(0, 0);
private boolean canJump = true;
int jumpNumber;
Label jumpCount = new Label();
Button jumpCountButton = new Button();
private Node createObject(int x, int y, int w, int h, Color color) {
Rectangle object = new Rectangle(w, h);
object.setTranslateX(x);
object.setTranslateY(y);
object.setFill(color);
blockContainer.getChildren().addAll(object);
return object;
}
private void MainPage() {
Rectangle bg = new Rectangle(1280, 720, Color.LIGHTSKYBLUE);
//점프관련
jumpNumber = 1; //최초생성값
jumpCount.setText("JUMP COUNT "+jumpNumber);
jumpCountButton.setLayoutX(10);
jumpCountButton.setOpacity(0);
jumpCountButton.setOnKeyPressed(e->{
if (e.getCode() == KeyCode.SPACE
&& player.getTranslateY() > -100
&& jumpNumber > 0 ) {
jumpNumber--;
jumpCount.setText("JUMP COUNT "+jumpNumber);
jumpPlayer();
}
});
//
levelWidth = ObjectData.LEVEL1[0].length() * 10;
for (int i = 0; i < ObjectData.LEVEL1.length; i++) {
String line = ObjectData.LEVEL1[i];
for (int j = 0; j < line.length(); j++) {
switch (line.charAt(j)) {
case '0':
break;
case '1':
Node block = createObject(j*10, i*10, 10, 10, Color.LIGHTGREEN);
blocks.add(block);
break;
case '2':
Node energy = createObject(j*10, i*10, 5, 5, Color.ORANGE);
energys.add(energy);
break;
case '3':
Node door = createObject(j*10, i*10, 10, 10, Color.BLACK);
doors.add(door);
break;
case '4':
Node sunR = createObject(j*10, i*10, 10, 10, Color.TOMATO);
doors.add(sunR);
break;
case '5':
Node sunY = createObject(j*10, i*10, 10, 10, Color.YELLOW);
doors.add(sunY);
break;
case '6':
Node cloud = createObject(j*10, i*10, 10, 10, Color.WHITE);
doors.add(cloud);
break;
}
}
}
player = createObject(0, 600, 20, 20, Color.DODGERBLUE);
player.translateXProperty().addListener((obs, old, newValue) -> {
int offset = newValue.intValue();
if (offset > 640 && offset < levelWidth - 640) {
blockContainer.setLayoutX(-(offset - 640));
}
});
mainContainer.getChildren().addAll(bg, blockContainer, jumpCount, jumpCountButton);
}
private boolean isPressed(KeyCode key) {
return keys.getOrDefault(key, false);
//keys객체를 만드는 HashMap클래스에 쓰이는 메소드 getOrDefault = key가 존재하면 key값을 반환하고 존재하지않으면 디폴트값인 false를 반환
}
private void sceneUpdate() {
// AnimationTimer로 1프레임마다 업데이트
if (isPressed(KeyCode.LEFT) && player.getTranslateX() > 0) {
// LEFT키를 누르고 player객체의 x값이 0보다 크거나 같다면 movePlayerX의 매개변수로 -2를 입력
movePlayerX(-6);
}
if (isPressed(KeyCode.RIGHT) && player.getTranslateX() + 40 <= levelWidth - 5) { // RIGHT키를 누르고 player객체의 x값+20(player객체크기)이 맵의 WIDTH보다 작거나 같다면 movePlayerX의 매개변수로 2를 입력
movePlayerX(6);
}
if (playerVelocity.getY() < 10) {
playerVelocity = playerVelocity.add(0, 2);
//playerVelocity의 y값이 10보다 작으면 1프레임당 y값 1씩추가
}
movePlayerY((int)playerVelocity.getY());
//movePlayerY(int value)에 playerVelocity값 할당 (낙하담당값이라서 연속적으로 실행되야함)
}
private void movePlayerX(int value) {
boolean movingRight = value > 0;
// LEFT=false, RIGHT=true
for (int i = 0; i < Math.abs(value); i++) {
for (Node block : blocks) {
//만들어서 objects라는 객체로 만들어놓은 ArrayList에 넣어둔 block를 하나씩 player와 비교 -> block노드를 사용가능
if (player.getBoundsInParent().intersects(block.getBoundsInParent())) {
if (movingRight) { //RIGHT
if (player.getTranslateX() + 20 == block.getTranslateX()) { // 우측방향 이동시 player의 x값은 block+20 block의 x값과 같다면
if(player.getTranslateY()+10 < block.getTranslateY()) { // player의 y값+10이 block의 y값보다 작다면 y값을 -10해준다
player.setTranslateY(player.getTranslateY()-10);
}
return;
}
} else { //LEFT
if (player.getTranslateX() == block.getTranslateX() + 10) { // 좌측방향 이동시 player의 x값과 block의 x값+10이 같다면
if(player.getTranslateY()+10 < block.getTranslateY()) { // player의 y값+10이 block의 y값보다 작다면 y값을 -10해준다
player.setTranslateY(player.getTranslateY()-10);
}
return;
}
}
}
}
player.setTranslateX(player.getTranslateX()+(movingRight ? 1 : -1)); // RIGHT버튼을 누르면 player객체의 x위치를 +1만큼씩, LEFT버튼을 누르면 x위치를 -1만큼씩이
}
for (Node energy : energys) {
if (player.getBoundsInParent().intersects(energy.getBoundsInParent())) {
jumpNumber = jumpNumber+1;
jumpCount.setText("JUMP COUNT "+jumpNumber);
energy.setTranslateY(energy.getTranslateY()+500);//energy 먹으면 jumpNumber+1, energy 사라지
}
}
for (Node door : doors) {
if (player.getBoundsInParent().intersects(door.getBoundsInParent())) {
System.out.println("door touch");
}
}
}
private void movePlayerY(int value) {
boolean movingDown = value > 0;
for (int i = 0; i < Math.abs(value); i++) {
for (Node block : blocks) {
if (player.getBoundsInParent().intersects(block.getBoundsInParent())) { //player와 block비교
if (movingDown) {
if (player.getTranslateY() + 20 == block.getTranslateY()) { // player객체 y값 +20(객체높이) = block객체 y값 이라면
player.setTranslateY(player.getTranslateY() - 1); // player객체의 y값을 -1해주고 canJump메소드 활성화
canJump=true;
return;
}
} else {
if (player.getTranslateY() == block.getTranslateY() + 9) { // 점프시 윗벽이 막혀있으면 더 안올라가짐
canJump=false;
return;
}
}
}
}
player.setTranslateY(player.getTranslateY()+(movingDown ? 1 : -1)); //player객체의 위치 = player객체의 이동좌표+ movingDown이 참이라면 +1 거짓이면 -1
}
for (Node door : doors) {
if (player.getBoundsInParent().intersects(door.getBoundsInParent())) {
System.out.println("door touch");
}
}
}
private void jumpPlayer() {
if (canJump) {
playerVelocity = playerVelocity.add(0, -35);
canJump = false;
}
}
//
@Override
public void start(Stage primaryStage) {
MainPage();
Scene scene = new Scene(mainContainer);
scene.setOnKeyPressed(e -> keys.put(e.getCode(), true));
scene.setOnKeyReleased(e -> keys.put(e.getCode(), false));
primaryStage.setTitle("JAVADOT");
primaryStage.setScene(scene);
primaryStage.show();
AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long now) {
sceneUpdate();
}
};
timer.start();
}
public static void main(String[] args) {
launch(args);
}
}
변경된 코드
1. 배경화면 변경 (ObjectData클래스를 참조하는 MainPage메서드를 통해 배경화면 구현)
MainPage()메서드에 포함되는 다음 코드들을 통해 객체들을 생성
0=빈값, 1=녹색, 2=주황색, 3=검정색, 4=빨간색, 5=노란색
levelWidth = ObjectData.LEVEL1[0].length() * 10;
for (int i = 0; i < ObjectData.LEVEL1.length; i++) {
String line = ObjectData.LEVEL1[i];
for (int j = 0; j < line.length(); j++) {
switch (line.charAt(j)) {
case '0':
break;
case '1':
Node block = createObject(j*10, i*10, 10, 10, Color.LIGHTGREEN);
blocks.add(block);
break;
case '2':
Node energy = createObject(j*10, i*10, 5, 5, Color.ORANGE);
energys.add(energy);
break;
case '3':
Node door = createObject(j*10, i*10, 10, 10, Color.BLACK);
doors.add(door);
break;
case '4':
Node sunR = createObject(j*10, i*10, 10, 10, Color.TOMATO);
doors.add(sunR);
break;
case '5':
Node sunY = createObject(j*10, i*10, 10, 10, Color.YELLOW);
doors.add(sunY);
break;
case '6':
Node cloud = createObject(j*10, i*10, 10, 10, Color.WHITE);
doors.add(cloud);
break;
}
}
}
2. energy구현
for (Node energy : energys) {
if (player.getBoundsInParent().intersects(energy.getBoundsInParent())) {
jumpNumber = jumpNumber+1;
jumpCount.setText("JUMP COUNT "+jumpNumber);
energy.setTranslateY(energy.getTranslateY()+500);
}
}
// player와 energy가 충돌하면
// 1. jumpNumber을 1 더해준다
// 2. jumpCount.setText를 통해 화면에 변경된 값을 출력해준다.
// 3. energy의 Y좌표를 +500해줘서 화면밖으로 사라지게 구현한다
3. jumpCounter 구현
int jumpNumber;
Label jumpCount = new Label();
Button jumpCountButton = new Button();
//변수추가, Label추가, Button추가
///////////////////////////////////////////////////
private void MainPage() {
jumpNumber = 1; //최초생성값
jumpCount.setText("JUMP COUNT "+jumpNumber);
jumpCountButton.setLayoutX(10);
jumpCountButton.setOpacity(0);
jumpCountButton.setOnKeyPressed(e->{
if (e.getCode() == KeyCode.SPACE && player.getTranslateY() > -100 && jumpNumber > 0 ) {
jumpNumber--;
jumpCount.setText("JUMP COUNT "+jumpNumber);
jumpPlayer();
}
});
mainContainer.getChildren().addAll(bg, blockContainer, jumpCount, jumpCountButton);
}
//최초 시작시 점프횟수 1 할당
// 화면에 출력될 Label인 jumpCount추가
// 키입력이벤트를 수행할 jumCountButton추가, 투명하게 배치
// 스페이스바를 누르면 jumpNumber은 1감소, Label에 변경된값을 출력한 후 jumpPlayer()실행,
4. door 구현
private ArrayList<Node> doors = new ArrayList<Node>();
// ArrayList로 door객체 생성
for (Node door : doors) {
if (player.getBoundsInParent().intersects(door.getBoundsInParent())) {
System.out.println("door touch");
}
}
}
//player객체와 door객체 충돌시 콘솔로그에 "door touch" 출력
// 추후에 다음스테이지로 넘어가도록 변경예정
'프로그래밍 > 개인프로젝트' 카테고리의 다른 글
(GIT) 생활코딩 - POSIX CLI1 (0) | 2021.07.18 |
---|---|
게임만들기(4) - "JAVADOT" 플랫폼게임 (0) | 2021.07.14 |
게임만들기(2) - "JAVADOT" 플랫폼게임 (0) | 2021.07.09 |
게임만들기(1) - "JAVADOT" 플랫폼게임 (0) | 2021.07.08 |
변수의 기본형 데이터 타입 사용시 (효율중시, 성능중시) (0) | 2021.06.22 |