先做分析,需求分析?不就是简单的一些想法实现。 dota有英雄,有小兵,我的游戏也要有英雄,还有一大堆的比如商人,动物之类的东西。我可不想每一个都写一个类。所以提取共性,创造父类。Unit 代表所有单位,他们有坐标,必须要有显示在窗口的能力。然后英雄有比单位多一些什么,比如技能,属性,可以***别人,可以操控移动……而敌人也有一堆属性,但他们都是单位,都有单位必须有的方法。
看下面的代码:(因为懒得写一些特殊的敌人,所以就没有将Unit完全抽象出来,而是直接作为敌人来表示。)
package demo01;
import java.awt.event.*; import java.awt.*; import java.util.*; public class Unit implements ShowElem, Runnable {//ShowElem 是一个定义的接口,只有一个方法show用来提醒我必须写show方法。当然也有其它用处 public int health = 100;//一些属性都有初始值这样你就可以为这个类用main方法测试,看看得到的数据是不是符合自己预期。 public int id = 0; public String s = "not define"; int x = 0, y = 0; private int width=30,height=30; private int cd = 1000; private int speedx=10,speedy=10;//速度分为x和y为了计算方便。 public void setxspeed(int i){ this.speedx=i; } public int getxspeed(){ return this.speedx; } public int getyspeed(){ return this.speedy; } public void setyspeed(int i){ this.speedy=i; } private boolean islive = true;//后来添加的,判断单位是否挂了。 public boolean islive(){ return this.islive; } public int getw() { return this.width; } public int geth(){ return this.height; } private Gun gun = new Ak47();//枪类,这个其实就是一个技能接口,枪的涉及难道和白虎的穿云箭不像吗? private DataBank dataBank = DataBank.init(); Thread t = new Thread(this);//线程,除非游戏结束要不然这个单位还是要不停在屏幕上运动的 Random rnd = new Random(); Unit() { t.start(); this.dataBank.add(this); this.id = this.dataBank.uSize() - 1; } Unit(int x, int y) { t.start(); this.x = x; this.y = y; this.dataBank.add(this); this.id = this.dataBank.uSize() - 1; } Unit(String s, int x, int y) { t.start(); this.s = s; this.x = x; this.y = y; this.dataBank.add(this); this.id = this.dataBank.uSize() - 1; } public void setGun(Gun gun) { this.gun = gun; } public Gun getGun() { return this.gun; } public void action() { ActionType.move(this); } public int getx() { return x; } public int gety() { return y; } public void show(Graphics g) {//这里可以换成贴图,但是我懒的找图,就画个圆吧,带个血条。 if(this.islive){ g.setColor(Color.blue); g.drawRect(x, y-5, width, 5); g.fillRect(x, y-5, width*health/100, 5); g.drawOval(x, y, width, height); } } public void run() {//我的run()写的不好,应该将里面的代码集合成一个action函数的,但是这是beta版能用就行了。 while (this.islive) { if(this.health<0){this.islive=false;break;} try { Thread.sleep(100); this.action(); this.cd -= 100; for (int i = 0; i < DataBank.data.uSize(); i++) { if (DataBank.data.uGet(i) != this) { if(this.cd<=0){ this.getGun().shoot(this, DataBank.data.uGet(i)); this.cd=1000; } } } } catch (InterruptedException e) { } } } public static void main(String[] args) {//每一个类里面都写main方法测试,这是一个好习惯,除非你完全确定自己写的类的效果。 Unit a = new Unit(); Unit b = new Unit("b", 20, 30); Unit c = new Unit("c", 30, 30); c.setGun(new Ak47()); DataBank db = DataBank.init();//DataBank 是什么?这个后面说 System.out.println(db.uSize()); System.out.println(db.uGet(0).x); System.out.println(a.id + " ," + b.id + " ," + c.id + c.getGun().getName()); try { Thread.sleep(2000); System.out.println(db.uGet(a.id).x + db.uGet(a.id).s); System.out.println(db.uGet(b.id).x + db.uGet(b.id).s); System.out.println(db.uGet(c.id).x + db.uGet(c.id).s); } catch (Exception e) {//里面没有操作,懒得写。运行结果符合自己预期。 } } }Unit类有了看Hero类
package demo01;
import java.awt.*; import java.awt.event.*; public class Hero extends Unit implements KeyListener, MouseListener {//这个英雄其实就是添加一个控制能力 Thread t = new Thread(this); Hero() { super(); t.start(); } Hero(String s, int x, int y) { super(s, x, y); t.start(); } public void show(Graphics g) {//方块显示英雄,既然是框架自然先将所有东西组合起来,我的设想里显示要有一个单独的模块的。这个只是凑合用。 g.setColor(Color.darkGray); g.fillRect(this.getx(), this.gety(), this.getw(), this.geth()); } public void keyPressed(KeyEvent e) {//按键移动 if (e.getKeyChar() == 'w') { this.y -= 10; } if (e.getKeyChar() == 's') { this.y += 10; } if (e.getKeyChar() == 'a') { this.x -= 10; } if (e.getKeyChar() == 'd') { this.x += 10; } } public void keyReleased(KeyEvent e) { } public void keyTyped(KeyEvent e) { } public void run() { } public void mouseClicked(MouseEvent e) { int mods = e.getModifiers(); if ((mods & InputEvent.BUTTON1_MASK) != 0) {//鼠标左键射击 this.getGun().shoot(this, e.getX(), e.getY()); } if ((mods & InputEvent.BUTTON3_MASK) != 0) {//鼠标右键移动 if ((e.getX() - this.x) > 0) { this.x += 10; } else { this.x -= 10; } if ((e.getY() - this.y) > 0) { this.y += 10; } else { this.y -= 10; } } } public void mouseExited(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } } 英雄方法没有写测试很短都不用测试了。我们能够获得了一个可以用作敌人的unit类和自己控制的hero类。但是一个动画里面有很多敌人,一个可以操控的英雄,我们怎么弄他们到手呢?它们在干什么?我必须用一个东西可以方便我找到所有的Unit。
DataBank:我来用来储存所有创建的需要显示的对象,它是一个类,但是必须是单例的,单例模式。其实就是静态数组啦。
package demo01;
import java.util.*; public class DataBank { static DataBank data = null; static int windowWidth=500;//定义一些常量,这样显得高端。 static int windowheight=500; List unitList = new ArrayList();//单位对象储存在表里 List bulletList = new ArrayList(); private DataBank() {//单例模式就是将构造函数似有化这样别人就不能新一个类了。 } public int add(Unit a) { this.unitList.add(a); return this.uSize(); } public int add(Bullet a) { this.bulletList.add(a); return this.bSize(); } public Unit uGet(int i) { return (Unit) this.unitList.get(i); } public void uDel(int i) { this.unitList.remove(i); } public Bullet bGet(int i) { return (Bullet) this.bulletList.get(i); } public int bSize() { return this.bulletList.size(); } public int uSize() { return this.unitList.size(); } public Object bRemove(int i) { return this.bulletList.remove(i); } public Object uRemove(int i) { return this.unitList.remove(i); } public static DataBank init() {//单例模式关键在这里,无论怎么干你只能获得一个对象。 if (data == null) { data = new DataBank(); return data; } else { return data; } } }Ok 既然有了枪就要有×××,其实和白虎的那个穿云箭的效果 一样。
package demo01;
import java.awt.*; public class Bullet implements ShowElem, Runnable { private int x = 0, y = 0, width=10, height=10; private int destx, desty; private int speed=15; private int range = 20; private boolean islive = false; private double degrees; private int un; public void setun(Unit a) { this.un = a.id; } Thread t = new Thread(this); Bullet() { } public void setSpeed(int s) { this.speed = s; } public void setrange(int s) { this.range = s; } public void show(Graphics g) {//这个是普通×××的显示,其实就是一个圈 if (this.islive) { g.setColor(Color.red); g.drawOval(this.x,this.y, this.width,this.height); } } public void setbullet(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; } public int getx() { return this.x; } public int gety() { return this.y; } public int getw() { return this.width; } public int geth(){ return this.height; } public void setlive() { this.islive = true; } public void setdie() {//×××生命周期是必须有的,要不然到最后就会创建一大堆的对象,然后挤占内存。 this.islive = false; } public void setdest(int x, int y) { this.setlive(); this.destx = x; this.desty = y; this.degrees = Math.atan((0.0 + this.desty - this.y) / (this.destx - this.x)); if(this.destx<this.x){ this.degrees+=Math.PI; } } public boolean islive() { return this.islive; } public void flyPoint() {// 计算×××飞行100毫秒后的位置。 this.range--; this.x = this.x +(int) (speed * Math.cos(this.degrees)); this.y = this.y + (int) (speed * Math.sin(this.degrees)); } public void run() { try { while (this.islive()) {// 如果×××存在 执行。 Thread.sleep(100); for (int i = 0; i < DataBank.data.uSize(); i++) { if (MyCheck.crash(this, DataBank.data.uGet(i))) { if (DataBank.data.uGet(i).id != this.un){ DataBank.data.uGet(i).health-=5; this.setdie();break;} } } this.flyPoint(); if (this.range <= 0) {// 射程到达 this.setdie();break;// ×××标记消失 } } } catch (InterruptedException e) { System.out.print("bullet is no running"); } } public static void main(String[] args){//×××测试类,每一个有稍微一点复杂算法的类我都测试一下。 Bullet db=new Bullet(); db.setbullet(50, 50, 50, 50); try{ System.out.println(db.getx()); Thread.sleep(1000); System.out.println(db.getx()); Thread.sleep(1000); System.out.println(db.getx()); }catch(Exception e){ System.out.println("mistake"); } } } 顺便贴出他的子类。package demo01;
import java.awt.*; public class BulletP47 extends Bullet { Thread t = new Thread(this); BulletP47() { super();//这个其实没必要。 t.start(); DataBank.data.add(this);//创建一个×××就将他放到表里。 } public void show(Graphics g) { if (super.islive()) { g.setColor(Color.red); g.drawOval(super.getx(), super.gety(), 10, 10); g.drawOval(super.getx() + 2, super.gety(), 10, 10); } } public void run() { super.run(); } }上面就不解释了,就是换个方法。
下面是枪类:
package demo01;
public abstract class Gun {//抽象方法 帅气 String name = "gun"; int bulletnum=1000; Gun(String a){ this.name=a; } public void setnum(int x) { this.bulletnum = x; } public String getName(){ return this.name; } abstract public void shoot(Unit a);//方法重构,这个可以用做自动射击,不同方法不同表现,具体实现在子类。 abstract public Bullet shoot(Unit a,Unit b); abstract public Bullet shoot(Unit a,int x,int y); } package demo01; public class Ak47 extends Gun { // Bullet bullet = new BulletP47(); Ak47() { super("Ak47"); } public void shoot(Unit a) { // this.bullet.setbullet(a.getx(), a.gety(), 10, 10); } public Bullet shoot(Unit a, Unit b) { this.bulletnum--; Bullet sb = new BulletP47(); if (bulletnum > 0) { sb.setun(a); sb.setbullet(a.getx(), a.gety(), 10, 10); sb.setdest(b.getx(), b.gety()); } return sb; } public Bullet shoot(Unit a,int x,int y){ this.bulletnum--; Bullet sb=new BulletP47(); if(this.bulletnum>0){ sb.setun(a); sb.setbullet(a.getx(),a.gety(),10,10); sb.setdest(x, y); } return sb; } } 枪类我是最喜欢的,因为用抽象更帅,不过其实是因为枪类简单,我就注意一下它的结构,最开始我只是要拿个能用的,现在慢慢的经过一部分测试,所以就注意形式了。ok 我把所有方法能静态的静态掉,这样不同类里都可以调用,这样省点事。
package demo01;
import java.util.*; public class ActionType { public static Random rnd = new Random(); public static int[][] rndfill(int[][] map,int max){//这个是我的随即地图生成,只是测试我的地图的,地图类贴上去还要改单位的action 还要写A*算法那就算了。 for(int i=0;i<map.length;i++){ for(int j=0;j<map[i].length;j++){ map[i][j]=rnd.nextInt(max); } } return map; } public static void movernd(Unit u) {// 随即移动动作。其实被我改了,变成边界碰撞,主要是随即移动像抽风。不过这一部分都是可以重写的。 int flag; int speedx, speedy; flag = rnd.nextInt(10); // System.out.println(flag); speedx = rnd.nextInt(20); speedy = rnd.nextInt(20); if (MyCheck.xTouchEdge(u, 500)) { u.x += speedx; } else { u.x -= speedx; } if (MyCheck.xTouchEdge(u, 500)) { u.y += speedy; } else { u.y -= speedy; } } public static Stack findRoad(int x,int y,int destx,int desty){//寻路,这就是了,没完成。 return null; } public static void move(Unit a) {//移动, if (MyCheck.xTouchEdge(a, 500)) { a.setxspeed(-a.getxspeed()); } a.x +=a.getxspeed(); if (MyCheck.yTouchEdge(a, 500)) { a.setyspeed(-a.getyspeed()); } a.y += a.getyspeed(); } }好了最后一个窗口,将所有东西显示出来并初步测试;
package demo01;
import java.awt.*; import java.awt.event.*; import java.util.Arrays; import javax.swing.*; class Cshow { public void paint(Graphics g){ g.setColor(Color.red); g.drawOval(30, 30, 30, 30); } } class Mypanel extends JPanel implements Runnable{ Thread t=new Thread(this);//一直没解释这个东西,就是线程,和Timer类差不多功效,但我是抄编程思想里面的写法。Timer类那时还不知道呢。 int x=100,y=100; //DElements d; DataBank db=DataBank.init();//其实db 和DataBank。static方法一样,但是这样后面可以剩写点东西。都一样 Cshow c; Mypanel(){ t.start(); c=new Cshow(); } public void paint(Graphics g){ //c.paint(g); g.setColor(this.getBackground()); g.fillRect(0, 0, this.getWidth(), this.getHeight()); MyMap.show(g);//其实我还有map地图实现,不过半成品,所有没贴上。 for(int i=0;i<db.uSize();i++){//迭代显示所有单位 db.uGet(i).show(g); if (db.uGet(i).health<0)db.uRemove(i); } for(int i=0;i<db.bSize();i++){//迭代显示所有×××。 db.bGet(i).show(g); if(!db.bGet(i).islive())db.bRemove(i);//×××挂了就消除,其实不一定要在这里调用的 //g.drawOval(i, i, i, i); } } public void run(){ while(true){//这个while()不停循环真是常用。 repaint(); try{ Thread.sleep(100); }catch(Exception e){ System.out.println("found a mistake"); } } } } public class Demo { public static void main(String[] args){//Demo 就是测试,自己随便试试可不可以用,正在写载入配置文件和存档文件,自动初始游戏,还有任务模式的实现,等到时候就将框架都写好了,那个时候就有时间关注细节了。 DataBank db=DataBank.init(); Bullet sb; int[][] democell=new int[10][10]; democell=ActionType.rndfill(democell, 4); MyMap.setcell(democell); Unit a=new Unit("a",100,40); Unit b=new Unit("b",30,30); Unit c=new Unit("c",100,130); Hero hero=new Hero("hero",100,300); db.add(sb=a.getGun().shoot(b, c)); try{ JFrame w=new JFrame("demo"); w.setSize(500,500); w.setLocationRelativeTo(null); w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Mypanel mp=new Mypanel(); MyButton mb=new MyButton(); mp.add(mb); mp.setLayout(null); mp.setSize(500, 500); w.add(mp); // w.addKeyListener(hero);//这一部分巧合遇到藏老师将focus然后就稍微改了改,但是有一个问题其实一直没解决,focus在setvisable方法后面会丢失键盘事件,奇怪,但没解释。真到想问问题的时候,总是找不到人。 // //mp.requestFocus(); // w.addMouseListener(hero); //mp.requestFocus(); w.setVisible(true); mp.addKeyListener(hero); mp.addMouseListener(hero); mp.requestFocus(); //w.show();//我喜欢原始版本的show 简单方便。 }catch(Exception e){ e.printStackTrace(); } } }PS:这个框架其实还是有很多问题,比如线程之间的并发,线程安全,需要设置标志位,或者其它之类的东西,但是能用了,那就有成就感,以后这些细节再处理。
而如果自己想写,那么就必须将Unit抽象化,而且很多东西必须添加,比如Unit的AI 我的AI是所有单位互相射击,你们可以自己写咯。比如都***英雄,比如英雄只可以向上射击,(这就是打飞机了!)比如死亡后创建一个战利品的对象,里面暴装备。OK 就到这里。希望大家给与修正建议。