游戏效果:
实现思路:
星星可以移动,篮子接到星星就加10分,该星星消失,
星星出界生命值就减1; 当减到0 的时候游戏就结束
游戏结束再次单击的时候游戏重新开始
游戏中涉及的对象
游戏本身
背景
星星
篮子
对象组成
背景: 一张图片即可
星星: x坐标 y坐标 宽度 高度 速度 图片
星星的行为 : 移动 越界
篮子:x坐标 y坐标 宽度 高度 图片
行为 : 接星星(星星碰撞)
游戏: 篮子 星星 背景 分数 生命值 是否创建篮子 窗口 鼠标移动的事件 绘图游戏状态
行为:创建星星 所有的星星移动 移除星星 篮子和星星撞击 开始动 绘图 鼠标移动
实现流程:
1.创建游戏本体(Game)
先完成游戏中的基本窗口信息,包括标题中的生命、分数等信息
public class Game{
//窗口
public static JFrame frame;
//分数
private int score;
//生命值
private int life;
//游戏状态
private int status;//0 标识未开始 1标识游戏中,2标识游戏结束
public Game(){
score = 0;
life =3;
status = 0;
frame = new JFrame();
}
public void start(){
//设置大小
frame.setSize(900,500);
//把组件画的图添加在窗口中
frame.add(this);
//关闭窗口关闭程序
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//不能改变大小
frame.setResizable(false);
//设置居中
frame.setLocationRelativeTo(null);
//设置标题
frame.setTitle("生命值:"+life+",得分:"+score);
//显示窗口
frame.setVisible(true);
}
}
测试窗口(Test):
public class Test {
public static void main(String[] args) {
Game g = new Game();
g.start();
}
}
2.给窗口加上背景(Background)
//创建背景类
public class Background {
private BufferedImage img;
public Background() {
try {
img = ImageIO.read(new File("src/bg.png"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
将背景图片绘制到窗口上:
========继承JComponent类
public class Game extends JComponent
========创建成员变量 Background
private Background bg;
========构造方法中实例化背景对象
public Game(){
bg = new Background();
}
========向Game类中加入画图方法(paint)
//重写JComponent类中的画图方法
@Override
public void paint(Graphics g) {
//画背景
g.drawImage(bg.getImg(),bg.getX(),bg.getY(),this);
}
3.星星(Star)
public class Star{
private BufferedImage img;
private int x;
private int y;
private int width;
private int height;
//星星下落速度
private int speed;
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Star() {
try {
img = ImageIO.read(new File("src/star.png"));
} catch (IOException e) {
throw new RuntimeException(e);
}
width =20;
height=20;
setY(-height);
//设置星星在x轴上随机生成
//Math.random() 生成0-1之间的随机数
setX((int)(Math.random()*(Game.frame.getWidth()-this.width)));
speed = (int)(1+6*Math.random());
}
//向下移动
public void move(){
setY(getY()+speed);
}
//是否越界
public boolean out(){
if(getY()>Game.frame.getHeight()){
return true;
}
return false;
}
}
将星星绘制到窗口上:
========创建成员变量 stars
//游戏中会出现很多星星 所以在这里我们使用集合来存放星星们
private List<Star> stars;
========构造方法中实例化星星集合对象
public Game(){
stars = new ArrayList<>();
}
========将画星星加入画图方法(paint)
//重写JComponent类中的画图方法
@Override
public void paint(Graphics g) {
//画星星
for (int i = 0; i < stars.size(); i++) {
Star star = stars.get(i);
g.drawImage(star.getImg(),star.getX(),star.getY(),star.getWidth(),star.getHeight(),this);
}
}
4.篮子(Basket)
public class Basket{
private BufferedImage img;
private int x;
private int y;
private int width;
private int height;
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public Basket() {
super("src/basket.png");
this.width =50;
this.height=60;
}
//是否撞到星星 是否接到星星
public boolean hitStar(Star star){
if(star.getX()>this.getX()-star.getWidth()&&star.getX()<this.getX()+this.width&&star.getY()>this.getY()-star.getHeight()&&star.getY()<this.getY()+this.height){
return true;
}
return false;
}
}
x轴的极限位置是1和2
位置1的x轴坐标是:篮子的x坐标-星星的宽度
位置2的x轴坐标是:篮子的x坐标+篮子的宽度
将篮子绘制到窗口上:
=======创建成员变量 basket isCreateBasket
private Basket basket;
//是否创建篮子 当用户点击开始游戏之后才创建篮子
private boolean isCreateBasket;
=======在构造函数中实例化
basket = new Basket()
=======创建鼠标监听事件(移动,点击)
//移动时创建篮子 并且跟随鼠标
//原理 篮子中心坐标与鼠标坐标一致
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
isCreateBasket =true;
basket.setX(e.getX()-basket.getWidth()/2);
basket.setY(e.getY()-basket.getHeight()/2);
if(basket.getX()<0){
basket.setX(0);
}
if(basket.getX()>frame.getWidth()-basket.getWidth()-5){
basket.setX(frame.getWidth()-basket.getWidth()-5);
}
if(basket.getY()<0){
basket.setY(0);
}
if(basket.getY()>frame.getHeight()-basket.getHeight()-30){
basket.setY(frame.getHeight()-basket.getHeight()-30);
}
}
});
//点击事件 单击鼠标 判断状态 开始游戏
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if(status==0||status==2){
status=1;
life = 3;
score =0;
stars.clear();
frame.setTitle("生命值:"+life+",得分:"+score);
}
}
});
}
=======画篮子
//画图
@Override
public void paint(Graphics g) {
//画篮子 先判断isCreateBasket 需要画篮子的时候才画
if(isCreateBasket){
g.drawImage(basket.getImg(),basket.getX(),basket.getY(),null);
}
}
5.游戏开始结束文字绘制到窗口上:
//画图
@Override
public void paint(Graphics g) {
Font f = new Font("黑体",Font.BOLD,30);
g.setFont(f);
g.setColor(Color.GREEN);
if(status==0){
g.drawString("点击开始游戏",350,200);
}else if (status==2){
g.drawString("游戏结束得分:"+score+",点击继续",250,200);
}
}
6.项目启动前的准备工作(action)
在start方法中调用!!!
public void action(){
int count = 0;
int spend;
while(true){
if(status==1){
//减缓星星生成速度
if(count%5==0){
//创建星星 并且加入到集合中
stars.add(new Star());
count = 5;
}
//下降速度根据分数改变
spend =slowDown(score);
count++;
//让星星开始移动
stars.forEach(star -> {
star.move();
});
//判断星星越界后的操作
removeStar();
//接到星星后的操作
hitStar();
try {
//通过线程休眠时间控制星星速度
Thread.sleep(spend);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//每次循环重绘窗口
repaint();
}
}
}
7.完善功能函数
=======星星越界removeStar
public void removeStar(){
for (int i = 0; i < stars.size(); i++) {
Star star = stars.get(i);
if(star.out()){
life--;
frame.setTitle("生命值:"+life+",得分:"+score);
stars.remove(star);
if(life<1){
status = 2;
}
}
}
}
========接星星hitStar
public void hitStar(){
for (int i = 0; i < stars.size(); i++) {
Star star = stars.get(i);
if(basket.hitStar(star)){
score+=10;
stars.remove(star);
frame.setTitle("生命值:"+life+",得分:"+score);
}
}
}
========通过分数改变下落速度slowDown
public int slowDown(int score){
if(score>10000){
return 10;
}else if(score>9000){
return 20;
}else if(score>8000){
return 30;
}else if(score>7000){
return 40;
}else if(score>6000){
return 50;
}else if(score>5000){
return 60;
}else if(score>4000){
return 70;
}else if(score>3000){
return 80;
}else if(score>2000){
return 90;
}else if (score>1000){
return 100;
}
return 200;
}
注:其中的背景图片 星星图片 以及篮子图片需自行添加寻找