一个java游戏
学习了一段时间的java萌生了用java写一个游戏的念头,希望通过写游戏的过程熟练java语法,在编写的过程中也遇到了诸多的问题,还好都克服了,也作出了一个相对比较完整的闯关类游戏(虽然游戏中还有很多的问题),在编写的过程中也对一些java的知识有了更多的理解。游戏中写了两类敌人,一类在空中飞,一类是地上走的,都能对英雄造成伤害,游戏界面中也加入了血条,蓝条,释放大招和发射魔法球都会消耗蓝条,打死敌人会增加蓝条。下面我说一下游戏的主要部分。(游戏中用到的素材大都来自于爱给网,如有侵权立即删除)
游戏结构
程序一共分了五个包
1.Main包------包含GameFrame类,是主界面的实现
2.Animals包---------包含Animal Tiger Boar Bird AnimalsFactory类,其中的游戏中的动物元素都继承自Animal类重写了一些方法,Tiger和AnimalsFactory都是单例模式,保证了只能生成一个对象,在AnimalsFactory中有一个Animal类型的对象容器用来盛放游戏场景中的动物元素,因为是Animal类型的所以继承自Animal的动物实体都可以向上转型并加入到容器中。并且AnimalsFactory中提供了对动物生死的观测。
3.Menus包 包含开始界面的实现类,(本来想在游戏界面上写几个菜单,但是因为各种原因还没有搞)
4.Tools包 有Bullet、Bbullet(野猪子弹)、 Ibullet(鸟子弹) 、MagicBall(魔法球)、 MagicBullet(魔法球释放的子弹)、 Tbullet(老虎的子弹) 、Tool 类,Tool作为所有的工具的基类,所有的子弹都继承自Bullet类。,并重写了Tool中的部分方法。
5.Map包Map类和Scene场景类。
游戏部分截图
(1)开始菜单界面
(嗯,没错,这个开始界面有点水。。。因为不想把太多的时间花费在ps上,不过游戏名字还是很霸气)
下面是开始界面的实现代码,用的JFrame,又添加了两个按钮。
package Menus;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import Main.GameFrame;
public class StartFrame extends JFrame{
private Toolkit tk=Toolkit.getDefaultToolkit();
private ImageIcon backGround=new ImageIcon("image/start.png");
private Image screenImage=null;
private StartFrame() {
}
private void drawStart() {
Font f=new Font("华文行楷",Font.BOLD,20);
JLabel label=new JLabel(backGround);
Button startButton=new Button("开始游戏");
Button ruleButton=new Button("游戏说明");
JPanel jp=new JPanel();
//jp.add(label);
jp.setBounds(0, 0, 600,800);
startButton.setBounds(250,200,110,50);
startButton.setBackground(Color.yellow);
startButton.setFont(f);
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
GameFrame game=new GameFrame();
close();
game.init();
}
});
ruleButton.setBackground(Color.yellow);
ruleButton.setBounds(250,300,110,50);
ruleButton.setFont(f);
label.setBounds(0, 0,600,800);
this.add(startButton);
this.add(ruleButton);
jp.add(label);
this.add(jp);
this.setLayout(null);
this.setBackground(Color.blue);
this.setResizable(false);
this.setLocation(650,150);
this.setSize(600,800);
this.setVisible(true);
}
private void close() {
this.setVisible(false);
}
public static void main(String[] args) {
StartFrame sf=new StartFrame();
sf.drawStart();
}
}
(2)游戏界面
主界面代码
package Main;
import Animals.Tiger;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import Map.Map;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
public class GameFrame extends Frame{
private static final long serialVersionUID = 1L;
public static int frameWidth=1400;
public static int frameHeight=800;
private Map map=new Map();
private Image screenImage = null;
public void init(){
this.setSize(frameWidth,frameHeight);
this.setLocation(260,120);
this.setTitle("动物世界");
this.setVisible(true);
this.setResizable(false);
this.addWindowListener(new WindowAdapter() { // 窗口关闭监听
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
screenImage=this.createImage(frameWidth,frameHeight);
this.addKeyListener(new KeyMonitor());
new Thread(new PaintThread()).start();
}
public void update(Graphics g){
Graphics gc=screenImage.getGraphics();
gc.setColor(Color.BLUE);
gc.fillRect(0, 0, frameWidth, frameHeight);
map.drawMap(gc);
drawInfo(gc);
g.drawImage(screenImage,0,0, null);//双缓冲
}
private void drawInfo(Graphics g) {
g.setFont(new Font("华文行楷",Font.BOLD,40));
g.drawString("魔法:",30,100);
g.fillRect(150,70,Tiger.magic,30);
g.setColor(Color.RED);
g.drawString("生命:",30,150);
g.fillRect(150,130,Tiger.life,30);
}
private class PaintThread implements Runnable{
public void run() {
while(Tiger.getTiger().ifPrint){
repaint();
try {
Thread.sleep(40);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
private class KeyMonitor extends KeyAdapter{
public void keyReleased(KeyEvent e) {
Tiger.getTiger().key_Released(e);
}
public void keyPressed(KeyEvent e) {
Tiger.getTiger().key_Pressed(e);
}
}
}
敌人随机产生的代码*
private void random(){
time++;
if(time%100==0){
int randY=random.nextInt(250)+400;
animals.add(new Boar(1400,randY));
if(randY>=550)
randY=400;
animals.add(new Boar(1400,randY+50+random.nextInt(50)));
Bird bird=new Bird(1400,30);
if(time%200==0)
animals.add(bird);
}
}
因为所有的动物都是继承自Animal,所以直有接建立一个Animal的对象容器,其中time就像是一个计时器,100个时间单位后会产生两只野猪,200个时间单位后就会产生一只鸟。并且野猪的产生位置是随机的,
而两只野猪相距要有一定距离否则会重合,所以r第二只野猪的y坐标是:randY+50+random.nextInt(50)
Scene实现场景的移动
public void drawScene(Graphics g,String direction,int x,int y) {
if(x>380&&direction.equals("Forward_go")&&scene_x<9700){
scene_x=scene_x+50;
}
if(scene_x==9700){
Tiger.getTiger().go=true;
if(x>1200) {
GameFrame.win=true;
}
}
g.drawImage(scene,0,0,GameFrame.frameWidth,GameFrame.frameHeight,scene_x,scene_y,scene_x+1400,scene_y+800,null);
}
}
(3)英雄大招
(事实上大招的伤害还没有写。。。因为写大招伤都是重复算坐标的工作,所以没有写。。。)
这里是大招特效的部分实现
public void drawBullet(Graphics g) {
if(number==0) {
g.drawImage(magicBullet[0],x,y,null);
y-=15;
}
if(number==1) {
g.drawImage(magicBullet[1],x,y,null);
x+=15;
y-=15;
}
if(number==2) {
g.drawImage(aperture[3],x-100,y-120,null);
g.drawImage(magicBullet[2],x,y,null);
x+=15;
}
if(number==3) {
g.drawImage(magicBullet[3],x,y,null);
x+=15;
y+=15;
}
if(number==4) {
g.drawImage(magicBullet[4],x,y,null);
y+=15;
}
if(number==5) {
g.drawImage(magicBullet[5],x,y,null);
x-=15;
y+=15;
}
if(number==6) {
g.drawImage(magicBullet[6],x,y,null);
x-=15;
}
if(number==7) {
g.drawImage(magicBullet[7],x,y,null);
x-=15;
y-=15;
}
}
一共有八个方向的子弹,分别标注0-7,不同的方向要展示不同的图片。、
public void observation(Graphics gc) {
for(int i=0;i<tiger.bullets.size();i++){//老虎的子弹打到敌人
for(int j=0;j<animals.size();j++){
if(animals.get(j) instanceof Boar) {
if(animals.get(j).ifHit(tiger.bullets.get(i).x, tiger.bullets.get(i).y)) {
animals.get(j).dead(gc);
animals.get(j).bomb(gc);
if(animals.get(j).life==0&&animals.get(j).bomb){
animals.remove(j);
tiger.bullets.get(i).live=false;
tiger.magic+=10;
}
}
}
}
}
for(int i=0;i<tiger.magicBall.magicBullets.size();i++)
for(int j=0;j<animals.size();j++) {
if(animals.get(j) instanceof Bird)
try {
if(tiger.magicBall.magicBullets.get(i).number==1) {
if(tiger.magicBall.magicBullets.get(i).judge(animals.get(j))) {
animals.remove(j);
tiger.magic+=10;
tiger.magicBall.magicBullets.remove(i);
}
}
}catch(IndexOutOfBoundsException e) {
System.out.println("数组越界了");
}
}
for(int i=0;i<animals.size();i++){ //子弹打老虎对老虎造成伤害
for(int j=0;j<animals.get(i).getBullet().size();j++) {//这里出现了一个错误,居然是忘记了重写父类中的getBullet方法
if(animals.get(i) instanceof Boar) {
int c=animals.get(i).getBullet().get(j).x+20;
int d=animals.get(i).getBullet().get(j).y+20;
if(c>tiger.x+256&&c<tiger.x+280&&d<tiger.y+255&&d>tiger.y+210){
Tiger.life-=3;
animals.get(i).getBullet().remove(j);
}
}else{
if(tiger.getRect().intersects(animals.get(i).getBullet().get(j).getRect())) {
Tiger.life-=4;
animals.get(i).getBullet().remove(j);
}
}
}
}
}
AnimalFactory类中的observation()方法是对地图中的子弹和对象进行监控,控制子弹的打中,这里写的比较差。。。到这里基本就差不多了最后再看一下老虎类的控制:
通过控制方向标记控制图片的展示:
public void key_Released(KeyEvent e){
int key=e.getKeyCode();
switch(key) {
case KeyEvent.VK_UP:
direction="Left";
break;
case KeyEvent.VK_DOWN:
direction="Right";
break;
case KeyEvent.VK_LEFT:
direction="Behind";
break;
case KeyEvent.VK_RIGHT:
direction="Forward";
break;
}
}
public Rectangle getRect() {
return new Rectangle(x+256,y+220,60,60);
}
public void key_Pressed(KeyEvent e) {
int key=e.getKeyCode();
switch(key) {
case KeyEvent.VK_UP:
direction="Left_go";
y=y-20;
break;
case KeyEvent.VK_DOWN:
direction="Right_go";
y=y+20;
break;
case KeyEvent.VK_LEFT:
direction="Behind_go";
x=x-15;
break;
case KeyEvent.VK_RIGHT:
direction="Forward_go";
if(x<400||go)
x=x+15;
break;
case KeyEvent.VK_Q:
if(magic<0)
break;
magic-=3;
fire=true;
if(direction.equals("Forward_go")||direction.equals("Forward")||direction.equals("Forward_fire")){
direction="Forward_fire";
bullets.add(new Tbullet(x+tigerImageWidth/2+15,y+tigerImageHeight/3+45,direction));
}
if(direction.equals("Behind_go")||direction.equals("Behind")||direction.equals("Behind_fire")) {
direction="Behind_fire";
bullets.add(new Tbullet(x+110,y+tigerImageHeight/2-40,direction));
}
break;
case KeyEvent.VK_E:
if(magic<0)
break;
magic-=3;
magicBall.e_Fire=true;
break;
case KeyEvent.VK_W:
if(magic<0)
break;
magic-=20;
magicBall.magicFire=true;
break;
}
}
这里是老虎的画图方法:
public void drawTiger(Graphics g) {
limitXY();
if(life<=0) {
dead(g);
return;
}
if(direction.equals("Right")){
if(step>=tiger_R.length)
step=0;
g.drawImage(tiger_R[step],x,y,null);
step++;
}
if(direction.equals("Left")){
if(step>=tiger_L.length)
step=0;
g.drawImage(tiger_L[step],x,y,null);
step++;
}
if(direction.equals("Forward")){
if(step>=tiger_F.length)
step=0;
g.drawImage(tiger_F[step],x,y,null);
step++;
}
if(direction.equals("Behind")){
if(step>=tiger_B.length)
step=0;
g.drawImage(tiger_B[step],x,y,null);
step++;
}
if(direction.equals("Forward_go")){
if(step>=tiger_Fgo.length)
step=0;
g.drawImage(tiger_Fgo[step],x,y,null);
step++;
}
if(direction.equals("Right_go")){
if(step>=tiger_Rgo.length)
step=0;
g.drawImage(tiger_Rgo[step],x,y,null);
step++;
}
if(direction.equals("Behind_go")) {
if(step>=tiger_Bgo.length)
step=0;
g.drawImage(tiger_Bgo[step],x,y,null);
step++;
}
if(direction.equals("Left_go")){
if(step>=tiger_Lgo.length)
step=0;
g.drawImage(tiger_Lgo[step],x,y,null);
step++;
}
if(direction.equals("Forward_fire")){
if(step>=tiger_Ffire.length)
step=0;
g.drawImage(tiger_Ffire[step],x,y,null);
step++;
}
if(direction.equals("Behind_fire")){
if(step>=tiger_Bfire.length)
step=0;
g.drawImage(tiger_Bfire[step],x,y,null);
step++;
}
}
以上就是这个游戏的基本实现,代码中还有诸多的问题,欢迎大家指出,虽然awt Swing已经不太有人用了,但是写写小游戏还是可以的,这样既能提高兴趣又能训练自己的java基本语法。学习本来就应该是一件快乐有成就感的事情。
需要源码请评论联系我
`