此文章仅作为自己学习过程中的记录和总结,同时会有意地去用英文来做笔记,一些术语的英译不太准确,内容如有错漏也请多指教,谢谢!
一、包结构
- Creature 所有其他生物的父类
- Chomper 食人花
- Fungus 怪物
- Mushroom 蘑菇
- Turtle 乌龟
- Actions 人物当前行为
- Direction 人物/其他生物当前所朝方向
- Hero 人物的父类
- Opponent 敌人(最终未用到)
- Zario 主角
- Box 盒子
- Brick 砖块
- Grass 草地
- Material 所有物体的父类
- Pipe 管道
- Tower 通关处的城堡
二、具体实现 —— material
2.1 Material
- Material.java
/*
* Material
*
* 2020/11/28 15:36
*
* Zay
*/
package domain.material;
import domain.creature.Creature;
import domain.hero.Actions;
import domain.hero.Hero;
import ui.MainFrame;
import web.client.GameClient;
import java.awt.*;
import static ui.MainFrame.*;
import static web.client.GameClient.getGameClient;
/**
* <p>The attributes and related methods of the materials
* in the game like grass, pipe and so on.</p>
* * @author Zay
* @version 2020/11/28 15:36
*/
public class Material {
//The normal width of the materials.
private static final int WIDTH = 28;
//The normal height of the materials.
private static final int HEIGHT = 28;
//A Toolkit instance.
private static Toolkit toolkit = Toolkit.getDefaultToolkit();
//An array of Images containing the images to be shown.
private static Image[] images = null;
//The x coordinate of the domain.material.
private int x_axis;
//The y coordinate of the domain.material.
private int y_axis;
//The sum of the distance in x axis that has been run.
private int x_hasRun = 0;
//Store a expected value.
private int initial_x_axis;
//The common width of the materials.
private int common_width;
//The common height of the materials.
private int common_height;
//The total width of the domain.material, since some materials are composed of several materials.(Ground, bricks)
private int total_width = 0;
//The total height of the domain.material, since some materials are composed of several materials.(Ground, bricks)
private int total_height = 0;
//Judging if the domain.material has been drawn or not.
private boolean drawn = true;
//Judging if the domain.material is still available so that
//we can decide whether to repaint it or not.
private boolean available = true;
//The main character instance.
private Hero player = null;
//The actions for the main character.
private Actions actions = Actions.UNSTAND;
//The actions for the main character.
private Actions touch = Actions.UNTOUCH;
//The actions for the main character.
private Actions touchHero = Actions.UNTOUCH;
//A MainFrame instance.
private MainFrame mainFrame;
//The main frame of the game.
private GameClient gameClient;
/**
* Initialize the basic attributes.
*
* @param x_axis The x coordinate of the domain.material.
* @param y_axis The y coordinate of the domain.material.
* @param mainFrame A MainFrame instance.
*/
public Material(int x_axis, int y_axis, MainFrame mainFrame) {
common_width = WIDTH;
common_height = HEIGHT;
initial_x_axis = x_axis;
this.x_axis = x_axis;
this.y_axis = y_axis;
this.mainFrame = mainFrame;
gameClient = getGameClient();
}
/**
* Check if the domain.material is available. If yes, repaint the domain.material.
* Else, don't repaint it.
*/
public void draw(Graphics graphics) {
checkIfAvailable();
getHasrun();
hitHero(gameClient.getPlayer1());
move();
}
/**
* Examine if the domain.material is still available
* so that we can decide whether to repaint it or not.
*/
public void checkIfAvailable() {
if (!available) {
return;
}
//If the domain.material is not in the bounds of the window.
if (!getRectangle().intersects(new Rectangle(0, 0, FRAME_WIDTH, FRAME_HEIGHT))) {
//If the domain.material is no longer in the valid range of the map.
if (x_axis <= -FRAME_WIDTH / 2) {
drawn = false;
available = false;
}
}
}
/**
* Get the distance in the x axis that the domain.hero has run.
*/
public void getHasrun() {
x_hasRun = gameClient.getPlayer1().getHasrun_x();
}
/**
* The logical part of the domain.hero's moving.
*/
public void move() {
if (available) {
player = gameClient.getPlayer1();
}
{
if ((player.getX_axis() + player.getX_speed() > RIGHT_BORDER)
&& (!player.isGame_finished())) {
x_axis -= player.getX_speed();
}
}
}
/**
* Like an abstract method. Models the part of hitting domain.hero of the creatures.
*/
public void hitHero(Hero hero) {
if (!this.isDrawn()) {
return;
}
}
/**
* Like an abstract method. Models the actions of different materials.
*/
public void action() {
}
/**
* By getting the x, y coordinate as well as the width and height of the examined rectangle.
* That is, the rectangle is made up of the x, y coordinate as well as the width and height we got.
* Then we can use it to examine whether or not there is a collision between materials and domain.hero.
*/
public boolean checkIfThroughHero(Hero hero) {
//The x and y coordinate of the domain.hero at the current frame.
int x_now, y_now;
//The x and y coordinate of the domain.hero at the next frame.
int x_nextFrame, y_nextFrame;
//The x and y coordinate of the rectangle created by the domain.hero's moving.
int x_rectangle, y_rectangle;
//The width and height of the rectangle created by the domain.hero's moving.
int width_rectangle, height_rectangle;
//The rectangle made up of the x, y coordinate as well as the width and height above.
//So that we can use it to examine collision.
Rectangle examine_rec;
x_now = hero.getX_axis();
y_now = hero.getY_axis();
x_nextFrame = hero.getX_axis() + hero.getX_speed();
y_nextFrame = hero.getY_axis() + hero.getY_speed();
x_rectangle = Math.min(x_now, x_nextFrame); //When the domain.hero is moving forward(right).
y_rectangle = Math.max(y_now, y_nextFrame); //When the domain.hero is moving upside.
if (hero.getX_speed() > 0) {
width_rectangle = hero.getX_speed();
} else {
width_rectangle = -hero.getX_speed();
}
if (hero.getY_speed() > 0) {
height_rectangle = hero.getY_speed();
} else {
height_rectangle = -hero.getY_speed();
}
examine_rec = new Rectangle(x_rectangle, y_rectangle, width_rectangle, height_rectangle);
return examine_rec.intersects(this.getRectangle());
}
/**
* By getting the x, y coordinate as well as the width and height of the examined rectangle.
* That is, the rectangle is made up of the x, y coordinate as well as the width and height we got.
* Then we can use it to examine whether or not there is a collision between materials and domain.creature.
*/
public boolean checkIfThroughCreature(Creature creature) {
//The x and y coordinate of the domain.creature at the current frame.
int x_now, y_now;
//The x and y coordinate of the domain.creature at the next frame.
int x_nextFrame, y_nextFrame;
//The x and y coordinate of the rectangle created by the domain.creature's moving.
int x_rectangle, y_rectangle;
//The width and height of the rectangle created by the domain.creature's moving.
int width_rectangle, height_rectangle;
//The rectangle made up of the x, y coordinate as well as the width and height above.
//So that we can use it to examine collision.
Rectangle examine_rec;
x_now = creature.getX_axis();
y_now = creature.getY_axis();
x_nextFrame = creature.getX_axis() + creature.getX_speed();
y_nextFrame = creature.getY_axis() + creature.getY_speed();
x_rectangle = Math.min(x_now, x_nextFrame); //When the domain.creature is moving forward(right).
y_rectangle = Math.max(y_now, y_nextFrame); //When the domain.creature is moving upside.
if (creature.getX_speed() > 0) {
width_rectangle = creature.getX_speed();
} else {
width_rectangle = -creature.getX_speed();
}
if (creature.getY_speed() > 0) {
height_rectangle = creature.getY_speed();
} else {
height_rectangle = -creature.getY_speed();
}
examine_rec = new Rectangle(x_rectangle, y_rectangle, width_rectangle, height_rectangle);
return examine_rec.intersects(this.getRectangle());
}
/**
* Get the {@code Rectangle} instance of the domain.material.
*
* @return A {@code Rectangle} instance of the domain.material.
*/
public Rectangle getRectangle() {
return new Rectangle(x_axis, y_axis, common_width, common_height);
}
public int getX_axis() {
return x_axis;
}
public void setX_axis(int x_axis) {
this.x_axis = x_axis;
}
public int getY_axis() {
return y_axis;
}
public void setY_axis(int y_axis) {
this.y_axis = y_axis;
}
public int getX_hasRun() {
return x_hasRun;
}
public int getInitial_x_axis() {
return initial_x_axis;
}
public int getCommon_width() {
return common_width;
}
public void setCommon_width(int common_width) {
this.common_width = common_width;
}
public int getCommon_height() {
return common_height;
}
public void setCommon_height(int common_height) {
this.common_height = common_height;
}
public int getTotal_width() {
return total_width;
}
public void setTotal_width(int total_width) {
this.total_width = total_width;
}
public int getTotal_height() {
return total_height;
}
public void setTotal_height(int total_height) {
this.total_height = total_height;
}
public boolean isDrawn() {
return drawn;
}
public boolean isAvailable() {
return available;
}
public void setAvailable(boolean available) {
this.available = available;
}
public Actions getActions() {
return actions;
}
public void setActions(Actions actions) {
this.actions = actions;
}
public Actions getTouch() {
return touch;
}
public void setTouch(Actions touch) {
this.touch = touch;
}
public Actions getTouchHero() {
return touchHero;
}
public void setTouchHero(Actions touchHero) {
this.touchHero = touchHero;
}
public MainFrame getMainFrame() {
return mainFrame;
}
public static Image[] getImages() {
return images;
}
public static void setImages(Image[] images) {
Material.images = images;
}
public static Toolkit getToolkit() {
return toolkit;
}
}
2.1 Box
/*
* Box
*
* 2020/11/28 16:48
*
* Zay
*/
package domain.material;
import domain.creature.Mushroom;
import domain.hero.Actions;
import domain.hero.Hero;
import ui.MainFrame;
import util.music.GameAudio;
import util.map.Background;
import java.awt.Graphics;
import java.awt.Image;
import java.util.HashMap;
import java.util.Map;
/**
* <p>The attributes and related methods of the domain.material Box,
* including the logical part of its being hit by the domain.hero and produces mushroom.</p>
*
* @author Zay
* @version 2020/11/28 16:48
*/
public class Box extends Material {
//The speed of the box in y axis when it's hit by the domain.hero.
public static final int BOX_Y_SPEED = 10;
//The acceleration of the box driven by the gravity.
public static final int BOX_G_ACC = 3;
//The common width of the box.
public static final int BOX_WIDTH = 30;
//The common height of the box.
public static final int BOX_HEIGHT = 30;
//The current speed of the box in y axis.
private int y_speed = 0;
//The initial y coordinate.
private int initial_y_axis;
//The loop time of the box's image changing.
private int loop_time = 1;
private static Map<String, Image> box_images = new HashMap<>();
//The mushroom item stored in the box.
private Mushroom mushroom = null;
static {
setImages(new Image[]{
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/box1.1.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/box1.2.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/box1.3.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/box1.4.png"))
});
box_images.put("Box_1", getImages()[0]);
box_images.put("Box_2", getImages()[1]);
box_images.put("Box_3", getImages()[2]);
box_images.put("Box_4", getImages()[3]);
}
/**
* Initialize the basic attributes.
*/
public Box(int x, int y, MainFrame mainFrame) {
super(x, y, mainFrame);
initial_y_axis = y;
setCommon_width(BOX_WIDTH);
setCommon_height(BOX_HEIGHT);
setTotal_width(BOX_WIDTH);
setTotal_height(BOX_HEIGHT);
}
/**
* Draw the box instance and make it loop images.
*/
public void draw(Graphics g) {
super.draw(g);
Image image = null;
if (loop_time <= 2) {
image = box_images.get("Box_1");
loop_time++;
} else if (loop_time <= 4) {
image = box_images.get("Box_2");
loop_time++;
} else if (loop_time <= 6) {
image = box_images.get("Box_3");
loop_time++;
} else if (loop_time <= 8) {
image = box_images.get("Box_4");
loop_time = 1;
}
g.drawImage(image, getX_axis(), getY_axis(), null);
if (mushroom != null) {
mushroom.draw(g);
}
}
/**
* Judge if the domain.hero hit the box and give corresponding reaction.
*/
public void hitHero(Hero hero) {
super.hitHero(hero);
if (!hero.isAlive()) {
return;
}
if (hero.getNextRectangle().intersects(this.getRectangle())) {
if (hero.getY_axis() >= getY_axis() + getTotal_height()) {
//If the domain.hero hit the box effectively.
setTouch(Actions.COLLIDE);
}
} else {
//If the domain.hero does not hit the box effectively.
setTouch(Actions.UNTOUCH);
}
action();
}
/**
* Models the process of the box being hit by the domain.hero and produces a mushroom.
*/
public void action() {
super.action();
if (getTouch() == Actions.COLLIDE) {
y_speed = -BOX_Y_SPEED;
if (mushroom == null){
mushroom = new Mushroom(getX_axis() + getCommon_width() / 5,
getY_axis() - 25, this, getMainFrame());
}
new GameAudio("HitBox").start();
} else if (getTouch() == Actions.UNTOUCH) {
if (getY_axis() < initial_y_axis) {
y_speed += BOX_G_ACC;
}
if (getY_axis() + y_speed > initial_y_axis) {
setY_axis(initial_y_axis);
y_speed = 0;
}
}
setY_axis(getY_axis() + y_speed);
}
}
2.2 Brick
/*
* Brick
*
* 2020/11/28 17:07
*
* Zay
*/
package domain.material;
import ui.MainFrame;
import util.map.Background;
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
/**
* <p>The attributes and related methods of the domain.material Brick.</p>
*
* @author Zay
* @version 2020/11/28 17:07
*/
public class Brick extends Material {
//The common width of the brick.
public static final int BRICK_WIDTH = 30;
//The common height of the brick.
public static final int BRICK_HEIGHT = 30;
private static Map<String, Image> brick_images = new HashMap<>();
//The number of the bricks in the row.
private int num_in_row;
//The number of the bricks in the column.
private int num_in_column;
//The name of the brick to be drawn.
private String brick_name;
static {
setImages(new Image[]{
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/brick_yellow3.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/brick_blue.png")),
});
brick_images.put("Brick_yellow", getImages()[0]);
brick_images.put("Brick_blue", getImages()[1]);
}
/**
* Initialize the basic attributes.
*/
public Brick(int x, int y, int width, int height, String brick_name, MainFrame mainFrame) {
super(x, y, mainFrame);
this.num_in_row = width;
this.num_in_column = height;
this.brick_name = brick_name;
setCommon_width(BRICK_WIDTH);
setCommon_height(BRICK_HEIGHT);
setTotal_width(getCommon_width() * width);
setTotal_height(getCommon_height() * height);
}
/**
* Draw the bricks.
*/
public void draw(Graphics g) {
super.draw(g);
Image image;
for (int width = 1; width <= num_in_row; width++) {
for (int height = 1; height <= num_in_column; height++) {
image = brick_images.get(brick_name);
g.drawImage(image, getX_axis() + ((width - 1) * getCommon_width()),
getY_axis() + ((height - 1) * getCommon_height()), null);
}
}
}
/**
* Get the {@code Rectangle} instance of the brick.
*
* @return A {@code Rectangle} instance of the brick.
*/
public Rectangle getRectangle() {
return new Rectangle(getX_axis(), getY_axis(), getCommon_width() * num_in_row,
getCommon_height() * num_in_column);
}
}
2.3 Grass
/*
* Grass
*
* 2020/11/28 17:20
*
* Zay
*/
package domain.material;
import ui.MainFrame;
import util.map.Background;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.util.HashMap;
import java.util.Map;
/**
* <p>The attributes and related methods of the domain.material Grass.</p>
*
* @author Zay
* @version 2020/11/28 17:20
*/
public class Grass extends Material {
//The number of the grasses in the row.
private int num_in_row;
//The number of the grasses in the column.
private int num_in_column;
private static Map<String, Image> grass_images = new HashMap<String, Image>();
static {
setImages(new Image[]{
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/grass_L1.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/grass_L2.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/grass_R1.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/grass_R2.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/grass1.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/grass2.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/grass3.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/grass_soil.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/grass_soil1.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/grass_soil2.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/grass_soil3.png")),
});
grass_images.put("GL1", getImages()[0]);
grass_images.put("GL2", getImages()[1]);
grass_images.put("GR1", getImages()[2]);
grass_images.put("GR2", getImages()[3]);
grass_images.put("G1", getImages()[4]);
grass_images.put("G2", getImages()[5]);
grass_images.put("G3", getImages()[6]);
grass_images.put("GS", getImages()[7]);
grass_images.put("GS1", getImages()[8]);
grass_images.put("GS2", getImages()[9]);
grass_images.put("GS3", getImages()[10]);
}
/**
* Initialize the basic attributes.
*/
public Grass(int x, int y, int num_in_row, int num_in_column, MainFrame mainFrame) {
super(x, y, mainFrame);
this.num_in_row = num_in_row;
this.num_in_column = num_in_column;
setTotal_width(getCommon_width() * num_in_row);
setTotal_height(getCommon_height() * num_in_column);
}
/**
* Draw the grasses.
*/
public void draw(Graphics g) {
super.draw(g);
int step = 1;
Image img = null;
for (int width = 1; width <= num_in_row; width++) {
for (int height = 1; height <= num_in_column; height++) {
if ((width == 1) && (height == 1)) {
//If the grass is at the first row and at the left.
img = grass_images.get("GL1");
} else if ((width == 1) && (height > 1)) {
//If the grass is not at the first row but at the left.
img = grass_images.get("GL2");
} else if ((width == num_in_row) && (height == 1)) {
//If the grass is at the first row and at the right.
img = grass_images.get("GR1");
} else if ((width == num_in_row) && (height > 1)) {
//If the grass is not at the first row but at the right.
img = grass_images.get("GR2");
} else if (height == 1) {
//If the grass is at the first row and not at the left or right side.
if (step == 1) {
img = grass_images.get("G1");
step++;
} else if (step == 2) {
img = grass_images.get("G2");
step++;
} else if (step == 3) {
img = grass_images.get("G3");
step = 1;
}
} else {
img = grass_images.get("GS");
}
g.drawImage(img, getX_axis() + (width - 1) * getCommon_width(),
getY_axis() + (height - 1) * getCommon_height(), null);
}
}
}
/**
* The logical part of the grass's moving.
*/
public void move() {
super.move();
}
/**
* Get the {@code Rectangle} instance of the Grass.
*
* @return A {@code Rectangle} instance of the Grass.
*/
public Rectangle getRectangle() {
return new Rectangle(getX_axis(), getY_axis(), getCommon_width() * num_in_row,
getCommon_height() * num_in_column);
}
}
2.4 Pipe
/*
* Pipe
*
* 2020/11/28 17:27
*
* Zay
*/
package domain.material;
import domain.creature.Chomper;
import domain.hero.Actions;
import domain.hero.Hero;
import ui.MainFrame;
import util.map.Background;
import java.awt.Graphics;
import java.awt.Image;
import java.util.HashMap;
import java.util.Map;
/**
* <p>The attributes and related methods of the domain.material Pipe.</p>
*
* @author Zay
* @version 2020/11/28 17:27
*/
public class Pipe extends Material {
//The common width of a pipe.
public static final int PIPE_WIDTH = 28;
//The common height of a pipe.
public static final int PIPE_HEIGHT = 28;
private static Map<String, Image> pipe_images = new HashMap<>();
//The number of pipes in the column.
private int num_in_column = 0;
//A Chomper instance.
private Chomper chomper = null;
static {
setImages(new Image[]{
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/pipe2.1.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/pipe2.2.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/pipe2.3.png")),
getToolkit().getImage(Background.class.getClassLoader().getResource("resource/image/pipe2.4.png")),
});
pipe_images.put("Pipe_1", getImages()[0]);
pipe_images.put("Pipe_2", getImages()[1]);
pipe_images.put("Pipe_3", getImages()[2]);
pipe_images.put("Pipe_4", getImages()[3]);
}
/**
* Initialize the basic attributes.
*/
public Pipe(int x, int y, int num_in_column, MainFrame mainFrame) {
super(x, y, mainFrame);
this.num_in_column = num_in_column;
setTotal_width(PIPE_WIDTH * 2);
setTotal_height(PIPE_HEIGHT * num_in_column);
}
/**
* Draw the pipes.
*/
public void draw(Graphics g) {
super.draw(g);
Image image = null;
if (chomper != null) {
chomper.draw(g);
}
for (int i = 1; i <= num_in_column; i++) {
for (int j = 1; j <= 2; j++) {
if (i == 1) {
if (j == 1) {
image = pipe_images.get("Pipe_1");
} else {
image = pipe_images.get("Pipe_2");
}
} else if (i > 1) {
if (j == 1) {
image = pipe_images.get("Pipe_3");
} else {
image = pipe_images.get("Pipe_4");
}
}
g.drawImage(image, getX_axis() + (j - 1) * PIPE_WIDTH,
getY_axis() + (i - 1) * PIPE_HEIGHT, null);
}
}
}
/**
* Judge if the domain.hero hit the box