java飞机大战心得体会
心得体会是指一种读书、实践后所写的感受性文字。语言类读书心得同数学札记相近;体会是指将学习的东西运用到实践中去,通过实践反思学习内容并记录下来的文字,近似于经验总结。下面是小编带来的有关java飞机大战心得体会,希望大家喜欢
java飞机大战心得体会1
1.首先有玩家类,窗口类,主函数类和图片文件(.jpg)
2.然后是先行知识,创建窗口(JFrame),设置窗口属性;窗口上不能直接添加组件(键盘监听等),所以先在窗口上添加容器(Jpanel),将组件(KeyAdapter)添加到容器;
3.画出玩家:重写窗口类中的paintComponent方法,创建Graphics对象,调用drawImage方法可画图,调用drawString方法可标注其名字
4.移动:在窗口类中创建键盘监听抽象类KeyAdapter(实现了接口的部分方法但无具体操作),需要重写该类的Keypressed方法和KeyRleased方法,赋给按键变量真值,随后将该对象添加到窗口
5.随机生成初始坐标:在开始游戏后随机给定玩家的x、y坐标,创建Random对象,调用Random.nextInt(n)方法,n代表从[0,n)区间的随机值。
6.最后通过一个Timer.schedule(匿名内部类对象,指定延迟后开始,周期)方法来实现移动效果。匿名内部类【TimerTask的子类,重写了run方法,包括repaint方法(实则调用paintComponent)和yidong方法】来重画、监听键盘的指令()并作出相应动作
下面是源代码(有注释):
容器类
package a;
import javax.swing._;
import java.awt._;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import static a.Newgame.frame;
//新建面板
public class War extends JPanel {
private Timer timer;
private boolean sUp, sDown, sRight, sLeft;//右飞机按键变量
private boolean sW, sD, sS, sA;//左飞机按键变量
private Player1 player1 = new Player1();
private Player2 player2 = new Player2();
private ImageIcon img11 = player1.img1;
private ImageIcon img22 = player2.img2;
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);//此句调用父类方法进行界面重绘,恢复到某个界面,下面的步骤再画玩家;如果注释掉会有重影
//在面板上画出玩家
g.drawImage(img11.getImage(), player1.x, player1.y, 100, 100, this);
g.drawString("P1", player1.x, player1.y);
g.drawImage(img22.getImage(), player2.x, player2.y, 100, 100, this);
g.drawString("P2", player2.x, player2.y);
}
public void startGame() {
timer = new Timer();
timer.schedule(new TimerTask() {//匿名内部类(TimerTask的子类)
@Override
public void run() {//重写run()函数
repaint();//调用重写的paintComponent来画两飞机
yidong();//并每次判断按下哪个键,然后移动
}
}, 0, 50);//安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。50毫秒执行一次
}
public void yidong() {
//因为每打印一次可能用户按下一个飞机的几个键或者两个飞机的几个键,这些是都要检测到的,改成else if后只能检测到一个键,无法实现两架飞机同时多方向移动
if (sW && player1.y > 0) {
player1.y -= player1.speed;
}
if (sA && player1.x > 0) {
player1.x -= player1.speed;
}
if (sS && player1.y < 700) {
player1.y += player1.speed;
}
if (sD && player1.x < 900) {
player1.x += player1.speed;
}
if (sUp && player2.y > 0) {
player2.y -= player2.speed;
}
if (sDown && player2.y < 700) {
player2.y += player2.speed;
}
if (sLeft && player2.x > 0) {
player2.x -= player2.speed;
}
if (sRight && player2.x < 900) {
player2.x += player2.speed;
}
}
public void act() {
//随机生成两飞机的初始坐标
Random rd = new Random();
player1.x = rd.nextInt(900);
player1.y = rd.nextInt(700);
player2.x = rd.nextInt(900);
player2.y = rd.nextInt(700);
//开始游戏后获得计时器开始监听并重画
startGame();
//KeyAdapter是KeyListener的实现类,重写了所有方法但没有具体操作
KeyAdapter keyAdapter = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_W:
sW = true;
break;
case KeyEvent.VK_A:
sA = true;
break;
case KeyEvent.VK_D:
sD = true;
break;
case KeyEvent.VK_S:
sS = true;
break;
case KeyEvent.VK_RIGHT:
sRight = true;
break;
case KeyEvent.VK_LEFT:
sLeft = true;
break;
case KeyEvent.VK_DOWN:
sDown = true;
break;
case KeyEvent.VK_UP:
sUp = true;
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_W:
sW = false;
break;
case KeyEvent.VK_A:
sA = false;
break;
case KeyEvent.VK_D:
sD = false;
break;
case KeyEvent.VK_S:
sS = false;
break;
case KeyEvent.VK_RIGHT:
sRight = false;
break;
case KeyEvent.VK_LEFT:
sLeft = false;
break;
case KeyEvent.VK_DOWN:
sDown = false;
break;
case KeyEvent.VK_UP:
sUp = false;
break;
}
}
};
frame.addKeyListener(keyAdapter);
}
}
主函数类:
package a;
import javax.swing._;
public class Newgame {
public static JFrame frame;
public static void main(String[] args) {
frame = new JFrame("逃出生天");
frame.setSize(1000,800);
//绝对布局组件位置和形状不会随窗体改变,不设置布局管理器就可以使用setBounds()来控制位置
frame.setLayout(null);
//设置窗体关闭程序自动关闭
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//窗体居中显示
frame.setLocationRelativeTo(null);
//添加主面板
War war = new War();
frame.add(war);
//设置面板大小
war.setBounds(0,0,1000,800);
//设置主面板可见
frame.add(war);
frame.setVisible(true);
war.act();
}
}
1234567891011121314151617181920212223242526
玩家类:
玩家1
package a;
import javax.swing._;
public class Player1 {
public int x;
public int y;
public int speed = 50;
public ImageIcon img1 = new ImageIcon("D:\\Program_Files\\Jetbrains\\workspace_idea\\src\\a\\plane.jpg");
}
12345678910
玩家2
package a;
import javax.swing._;
public class Player2 {
public int x;
public int y;
public int speed = 50;
public ImageIcon img2 = new ImageIcon("D:\\Program_Files\\Jetbrains\\workspace_idea\\src\\a\\plane2.jpg");
}
做成一个桌面小游戏:
点“+”号
选好主函数类后点ok
然后点Build中的Build Artificts
选择jar包点Build即可
然后jar包就在你的workspace生成了,找到它发送桌面快捷方式,更改图标名字即可
图片转换成图标的网站附上
java飞机大战心得体会2
用Java制作游戏之前,一定要做到方向明确,思路清晰。首先确定自己需要用到几个类,类里的内容大致是什么,用脑图进行表达展现。
Java语言是一种跨平台、适合于分布式计算环境的面向对象编程语言,具有简单性、面向对象、分布式,多线程性等,其中面向对象有封装,继承,多态三大特性。
1)封装:数据和基于数据的操作封装
2) 继承:一个对象直接使用另一个对象的属性和方法,子类可以继承父类
3) 多态:一个程序中同名的多个不同方法,实现多态的常见方法 子类对父类的覆盖,利用重载在同一个类中定义多个同名的不同方法;
Java游戏制作中必须有 public static void main(String[] args)的主方法,main()方法是程序执行的入口。例如我的飞机大战main(),便是游戏开始执行的入口,写在GameFace类中。
游戏框架的制作,其大部分的代码都是固定形式,可以通用。使用setVisible(true)的方法,改变默认的不可见状态,setLayout(null)取消默认的管理布局,然后setLocation(),setSize(),setBound()等方法设置其大小。将按钮添加监听,实现监听。在对应方法中编写代码,,为监听者创建对象,完成注册,即在接口名字前添加“add”。
游戏版面要继承JPanel,其原因是JPanel带有双缓冲技术,可以解决闪烁的问题,需要加入到JFrame窗体中,JPanel默认的布局管理器是FlowLayout。调用画笔,将所要显示的图片画出来。然后再根据自己的思路,在游戏版面内添加敌机,实现矩形碰撞,生命值判定,游戏结束对话框。要熟练掌握调用其他的类,画出分数,画出生命值。制作容器,装子弹,飞机,炸弹。
制作游戏思路一定要清晰,对于共有属性,可以建立一个父类,例如在创建一个FlyingObject类,这样可以避免代码的反复编写。对于子类myplane 、enemies可以直接继承父类,子类可以根据自己的需求再增加新的变量。在子类myplane中,画出我的飞机,控制飞机飞行的边界,调用子弹容器,画出容器中子弹,与敌机进行碰撞检测。飞机大战还应该实现键盘监听,例如Enter键实现暂停,上下左右键实现移动等。在敌机Enemies类中,定义敌机随机出现坐标,敌机图片的相对路径,敌机速度,敌机子弹与我的plane碰撞出现的结果以及敌机子弹生成的时间等。
游戏制作时需要注意的事项:1.JLabel的位置一定要放对,应当先添加背景JLabel,再添加其它控件。否则其它控件将被JLabel所遮挡。
2.对于多次重复编写的代码,尽可能的用for循环,简单方便。但是也要注意跳出语句的使用。
3.调用函数时要注意顺序
4.类名,方法名要遵循命名规范性,尽量做到见名知义,也要注意大小写。
java飞机大战心得体会3
线程:进程(process)就是一块包含了某些资源的内存区域。操作系统利用进程把它的工作划分为一些功能单元。 线程:进程中所包含的一个或多个执行单元称为线程(thread)。进程还拥有一个私有的虚拟地址空间,该空间仅能被它所包含的线程访问。 线程和进程的区别如下: 1)一个进程至少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 2)线程在执行过程中与进程的区别在于每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 3)从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用来实现进程的调度和管理以及资源分配。
2 简述线程的状态及其转换 1)New,创建一个线程,但是线程并没有进行任何的操作。 2)Runnable,新线程从New状态,调用start方法转换到Runnable状态。线程调用start方法向线程调度程序(JVM或者是操作系统)注册一个线程,这个时候一切就绪只等CPU的时间。 3)Running,从Runnable状态到Running状态,线程调度根据调度策略的不同调度不同的线程,被调度执行的线程进入Running状态,执行run方法。 4)Dead状态,从Running状态到Runnable,run方法运行完毕后,线程就会被抛弃,线程就进入Dead状态。 5)Block状态,从Running状态到Block状态,如果线程在运行的状态中因为I/O阻塞、调用了线程的sleep方法以及调用对象的wait方法则线程将进入阻塞状态,直到这些阻塞原因被结束,线程进入到Runnable状态。
3 简述线程的两种创建方式以及它们的区别 创建线程的两种方式: 1)使用Thread创建线程。Thread类是线程类,其每一个实例表示一个可以并发运行的线程。我们可以通过继承该类并重写run方法来定义一个具体的线程。其中重写run方法的目的是定义该线程要执行的逻辑。启动线程时调用线程的start()方法而非直接调用run()方法。start()方法会将当前线程纳入线程调度,使当前线程可以开始并发运行。当线程获取时间片段后会自动开始执行run方法中的逻辑。 2)使用Runnable创建线程。实现Runnable接口并重写run方法来定义线程体,然后在创建线程的时候将Runnable的实例传入并启动线程。 两种创建线程方式的区别: 使用Thread创建线程,编写简单,可以直接操纵线程,无需使用Thread.currentThread(),但是不能够再继承其他类。 使用Runnable创建线程可以将线程与线程要执行的任务分离开减少耦合,同时Java是单继承的,定义一个类实现Runnable接口,这样该类还可以继承自其他类。
多线程实现方法
使用Thread创建线并启动线程
java.lang.Thread类是线程类,其每一个实例表示一个可以并发运行的线程。我们可以通过继承该类并重写run方法来定义一个具体的线程。其中 重写run方法的目的是定义该线程要执行的逻辑。启动线程时调用线程的start()方法而非直接调用run()方法。start()方法会将当前线程纳入线程调 度,使当前线程可以开始并发运行。当线程获取时间片段后会自动开始执行run方法中的逻辑。
public class TestThread extends Thread{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("我是线程");
}
}
}
创建预启动线程
…
Thread thread = new TestThread();//实例化线程
thread.start();//启动线程
…
使用Runnable创建并启动线程
实现Runnable接口并重写run方法来定义线程体,然后在创建线程的时候将Runnable的实例传入并启动线程。 这样做的好处在于可以将线程与线程要执行的任务分离开减少耦合,同时java是单继承的,定义一个类实现Runnable接口这样的做法可以更好的 去实现其他父类或接口。因为接口是多继承关系。
public class TestRunnable implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("我是线程");
}
}
}
启动线程的方法:
…
Runnable runnable = new TestRunnable();
Thread thread = new Thread(runnable);//实例化线程并传入线程体
thread.start();//启动线程
…
使用内部类创建线程
通常我们可以通过匿名内部类的方式创建线程,使用该方式可以简化编写代码的复杂度,当一个线程仅需要一个实例时我们通常使用这种方式来 创建。 例如: 继承Thread方式:
Thread thread = new Thread(){ //匿名类方式创建线程
public void run(){
//线程体
}
};
thread.start();//启动线程
Runnable方式:
Runnable runnable = new Runnable(){ //匿名类方式创建线程
public void run(){
}
};
Thread thread = new Thread(runnable);
thread.start();//启动线程
线程的方法
currentThread:方法可以用于获取运行当前代码片段的线程
Thread current = Thread.currentThread();
获取线程信息 Thread提供了 获取线程信息的相关方法: long getId():返回该线程的标识符 String getName():返回该线程的名称 int getPriority():返回线程的优先级 Thread.state getState():获取线程的状态 boolean isAlive():测试线程是否处于活动状态 boolean isDaemon():测试线程是否为守护线程 boolean isInterrupted():测试线程是否已经中断
线程优先级
线程的切换是由线程调度控制的,我们无法通过代码来干涉,但是我们可以通过提高线程的优先级来最大程度的改善线程获取时间片的几率。 线程的优先级被划分为10级,值分别为1-10,其中1最低,10最高。线程提供了3个常量来表示最低,最高,以及默认优先级: Thread.MIN_PRIORITY, Thread.MAX_PRIORITY, Thread.NORM_PRIORITY 设置优先级的方法为:
void setPriority(int priority)
守护线程
守护线程与普通线程在表现上没有什么区别,我们只需要通过Thread提供的方法来设定即可: __void setDaemon(boolean )__ 当参数为true时该线程为守护线程。 守护线程的特点是,当进程中只剩下守护线程时,所有守护线程强制终止。 GC就是运行在一个守护线程上的。 需要注意的是,设置线程为后台线程要在该线程启动前设置。
Thread daemonThread = new Thread();
daemonThread.setDaemon(true);
daemonThread.start();
sleep方法
Thread的静态方法sleep用于使当前线程进入阻塞状态: __static void sleep(long ms)__ 该方法会使当前线程进入阻塞状态指定毫秒,当指定毫秒阻塞后,当前线程会重新进入Runnable状态,等待分配时间片。 该方法声明抛出一个InterruptException。所以在使用该方法时需要捕获这个异常 改程序可能会出现"跳秒"现象,因为阻塞一秒后线程并非是立刻回到running状态,而是出于runnable状态,等待获取时间片。那么这段等待 时间就是"误差"。所以以上程序并非严格意义上的每隔一秒钟执行一次输出。
yield方法:
Thread的静态方法yield: __static void yield()__ 该方法用于使当前线程主动让出当次CPU时间片回到Runnable状态,等待分配时间片。
join方法
__void join()__ 该方法用于等待当前线程结束。此方法是一个阻塞方法。 该方法声明抛出InterruptException。
线程同步
synchronized关键字 多个线程并发读写同一个临界资源时候会发生"线程并发安全问题“ 常见的临界资源: 多线程共享实例变量 多线程共享静态公共变量 若想解决线程安全问题,需要将异步的操作变为同步操作。 所谓异步操作是指多线程并发的操作,相当于各干各的。 所谓同步操作是指有先后顺序的操作,相当于你干完我再干。
同步代码块(synchronized 关键字 ),同步代码块包含两部分:一个作为锁的对象的引用,一个作为由这个锁保护的代码块 这个比较难理解故写了下面代码帮助理解
/__
_ 多线程并发安全问题
_ 当多个线程同时操作同一资源时,由于
_ 线程切换时机不确定,导致出现逻辑混乱。
_ 严重时可能导致系统崩溃。
_ @author ylg
_
_/
public class SyncDemo1 {
public static void main(String[] args) {
/_
_ 当一个方法中的局部内部类想引用该方法
_ 的其他局部变量时,这个变量必须被声明
_ 为final的
_/
final Table table = new Table();
Thread t1 = new Thread(){
public void run(){
while(true){
int bean = table.getBean();
Thread.yield();//模拟线程切换
System.out.println(
getName()+":"+bean
);
}
}
};
Thread t2 = new Thread(){
public void run(){
while(true){
int bean = table.getBean();
Thread.yield();//模拟线程切换
System.out.println(
getName()+":"+bean
);
}
}
};
t1.start();
t2.start();
}
}
class Table{
//20个豆子
private int beans = 20;
/__
_ 当一个方法被synchronized修饰后,该方法
_ 成为"同步方法"。多个线程不能同时进入到
_ 方法内部。
_ @return
_/
public synchronized int getBean(){
if(beans==0){
throw new RuntimeException("没有豆子了!");
}
Thread.yield();//模拟线程切换
return beans--;
}
}
/__
_ 有效的缩小同步范围可以保证在
_ 安全的前提下提高了并发的效率
_ @author ylg
_
_/
public class SyncDemo2 {
public static void main(String[] args) {
final Shop shop = new Shop();
Thread t1 = new Thread(){
public void run(){
shop.buy();
}
};
Thread t2 = new Thread(){
public void run(){
shop.buy();
}
};
t1.start();
t2.start();
}
}
class Shop{
/_
_ 在方法上使用synchroinzed,同步监视器对象即当前方法所属对象:this
_/
// public synchronized void buy(){
public void buy(){
try{
Thread t = Thread.currentThread();
System.out.println(t+"正在挑选衣服..");
Thread.sleep(5000);
/_
_ 同步块可以缩小同步范围。
_ 但是必须保证"同步监视器"即:"上锁对象"是同一个才可以。
_ 通常,在一个方法中使用this所谓同步监视器对象即可。
_/
synchronized (this) {
System.out.println(t+"正在试衣服..");
Thread.sleep(5000);
}
System.out.println(t+"结账离开");
}catch(Exception e){
}
}
}
/__
_ synchronized也成为"互斥锁"
_ 当synchronzed修饰的是两段代码,但是"锁对象"相同时,这两段代码就是互斥的。
_ @author ylg
_
_/
public class SyncDemo4 {
public static void main(String[] args) {
final Boo b = new Boo();
Thread t1 = new Thread(){
public void run(){
b.methodA();
}
};
Thread t2 = new Thread(){
public void run(){
b.methodB();
}
};
t1.start();
t2.start();
}
}
class Boo{
public synchronized void methodA(){
Thread t = Thread.currentThread();
System.out.println(t+"正在调用方法A");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
System.out.println(t+"调用方法A完毕");
}
public synchronized void methodB(){
Thread t = Thread.currentThread();
System.out.println(t+"正在调用方法B");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
System.out.println(t+"调用方法B完毕");
java飞机大战心得体会4
开发登录界面、设计地图加载、子弹飞机的加载、主控制程序的开发登录界面的开发,通常是在界面上显示游戏菜单选项,用户可根据菜单项选择需要的操作。菜单项是和游戏的功能紧密相关的。手机游戏的开发往往在界面和操作方式上有较高的要求,Java ME提供了低级界面开发的API,可用于游戏开发。低级界面画布类主要有Canvas和GameCanvas,其中Canvas是属于MIDP 1.0,GameCanvas则是属于MIDP 2.0。低级用户界面技术为用户提供了灵活的开发方法,可以进行一些较为底层的操作,例如:按键的处理事件更为丰富,组件位置的设置更为灵活。手机上的屏幕坐标系和我们常规数学的坐标系不相同。对于坐标(x,y),若x值越大,则越向右,y值越大,则越向下。对于飞机射击游戏,飞机在飞行过程中经过不同的地理环境,例如大海、小岛、石礁等作为地图的背景。地图的宽度通常要求能够自动匹配不同类型的手机宽度,高度则是以一个关卡所需的时间为依据进行设计。在此我们采用简化操作方法,给地图宽度和高度设置一个具体值。子弹的射击应该支持不同的方向,例如我方飞机自下而上发射子弹,敌方飞机自上而下发射子弹。当子弹与飞机碰撞之后,飞机的血量相应地要减少,如果飞机的血量为0,则产生爆炸效果,子弹和飞机都消失。飞机主角在开始游戏时出现在屏幕最底部的中间处,玩家可以通过上、下、左、右键控制其飞行方向,按下确认键后可以发射子弹。敌机在游戏开始后从背景上部出现,飞行,并发射子弹。在本任务中需要考虑敌机出现的位置,出现的数量和频率,飞行的速度和子弹的发射方向。
为了更好地控制游戏的主体逻辑,可以统一对游戏地图进行设置,对主角飞机、敌方飞机初始化,并在多线程中实现游戏的逻辑控制。
游戏主框架的首要模块的安排:
1.游戏的初始化。主要是完成游戏资源的加载,各种游戏对象、变量取值的初始化,游戏运行环境的获取和设置,历史记录的读取等。
2.游戏的主循环。执行游戏处理的主要代码,直到满足退出要求才停止循环,例如:玩家选择退出游戏,玩家游戏失败,玩家最终完成游戏等。主要实现分为三步:(1)获得游戏的输入信息;(2)处理游戏的逻辑;(3)更新游戏的画面
3.退出游戏
Canvas为抽象类,负责图形图像的绘制和用户交互。进行低级玩家界面的开发通常需要继承Canvas类,主要方法如下:
1.getHeight():获取Canvas绘图区域的高度。
2.getWidth():获取Canvas绘图区域的宽度。
3.paint(Graphics g):渲染画布,向屏幕画图,通常将画图的操作放在该方法中实现。当屏幕需要重新绘制时,Java ME主线程会自动调用paint方法,程序员不能在代码中直接声明调用该方法。
4.repaint():主动向系统请求刷新界面,具体的刷新操作实际是通过调用paint方法来完成。
5.isDoubleBuffered():判断手机设备是否匹配双缓冲。有些手机匹配双缓冲技术,有些则不匹配。
6.getGameAction(int keyCode):将手机的键值切换为游戏动作。
7.getKeyName(keyCode):得到按键的名字。
Graphics提供2D渲染能力,作用是在屏幕上绘制图形,类似于一支画笔。
Graphics绘制的图形不能够直接显示,必须通过Canvas或GameCanvas才能显示在屏幕上,因此Canvas和GameCanvas类似于可以显示图形的画布
Graphics类支持绘制图形主要包括以下3种:
(1)文本:可以设置文本的颜色、字体大小等
(2)图像:可以直接绘制图像文件或者从缓存中绘制
(3)2D几何图形:绘制点、直线、平面图形等
Graphics类没有构造方式,获取对象的途径有3种:
1.Canvas类中的paint方法有一个Graphics对象参数,系统会自动调用paint方法,并传进一个Graphics对象,因此可以在paint方法中使用Graphics对象编写绘图代码。
2.在GameCanvas类中通过getGraphics方法来获取一个Graphics对象,因此可以在要求的地方灵活地编写与绘图有关的代码。
3.Image对象的getGraphics()方法得到Graphics对象,可用于编写双缓冲区代码。
1.直接用整幅图片作为背景,再在上面重叠一层加入物件、摆设等,优点在于图形相对丰富、漂亮,但消耗资源较多,受手机硬件条件的影响不能做太大的图。
2.游戏地图是用一个个图块重复拼接成,而在程序中就可以通过一个较小的图像文件和一个二维数组,绘制出一幅较大的地图。具体的做法是将图像文件划分为若干个相同大小的图块(一般每个图块是16像素 × 16像素或者32像素 × 32像素),每个图块给一个索引值,例如:1表示草地图块,2表示砖头图块。而二维数据中记录的数字就是图像文件中的图块索引值,例如:某个数组元素的数值若为1,则表示在此处画草地。此方法的益处在于比较节约系统资源,可做出来的地图相对比较一般。
地图编辑器能够帮助将地图最后转变成程序直接使用,所以一个好的地图编辑器能够加速游戏的开发周期。
业界已经推出多款地图编辑器,例如Mappy(MapWin)、Tiled、TILE STUDIO等,其中Mappy功能比较强大,可以很方便地对2D地图进行编辑。
下载mayppy软件:HTTP:/ / www.tilemap.uk /mappy
假如需支持png图片,那么还需下载两个dll文件,这两个文件也都放在Mappy软件的网址上
zlib.dll用于文件压缩
libpng12.dll是PNG图像压缩库
将这两个文件下载复制到Mappy可执行文件的同一个目录下即可,否则在导入PNG文件时,会报图5-23的错误
制作游戏还需要用到图像素材,因此除了Mappy软件之外,还需要用到图像处理软件Photoshop来制作原始游戏素材。
J2SE中提供了多个接口和类管理集合,例如有Collection、List、Set、Map接口,实现接口的集合类有LinkedList、ArrayList、Vector、Hashtable、HashMap和WeakHashMap类。
在Java ME中只有java.util包提供Vector类,其功能和J2SE的Vector类似,实现的是一个动态增长的数组,可以在程序代码中调整或者裁减集合的大小,能向集合插入、删除和修改元素。
每一个集合中的元素都被分派一个整数索引号,能够直接根据索引号插入和删除一个元素,也能够修改和得到一个元素的值。
为了更好地控制游戏的主体逻辑,可以统一对游戏地图进行设置,对主角飞机、敌方飞机初始化,并在多线程中实现游戏的逻辑控制。