<
div id=”content” contentScore=”1293″>项目命名: JPhysicalEngine
项目目的: 自己爱好/毕业设计
项目人员: http://blog.csdn.net/kakashi8841
运行机器: Intel P8600 2.4GHz、2G内存、Intel GMA X4500 HD
开发环境: Linux Ubuntu 10.10
开发语言: Java
开发工具: Eclipse
项目描述: 使用Java开发的2D游戏物理引擎,可以使得以后开发类似愤怒的小鸟、雷电等物理、碰撞、动作类游戏可以更快速、更方便。
项目进度:
【已实现】
版本 完成日期 实现功能
V0.1 [2011-04-07] 大致框架
V0.2 [2011-04-11] 基本动画
V0.3 [2011-04-15] 恒力和AABB碰撞检测
V0.4 [2011-04-22] 框架优化、简单粒子系统
V0.5 [2011-05-05] 更精确的OBB碰撞检测
【待实现】
版本 计划完成日期 实现功能
V0.6 [2011-05-10] 变力
V0.7 [2011-05-12] 更完善的粒子系统
V0.8 [2011-05-17] 弹力、引力
V0.9 [2011-05-20] 框架优化、简单的输入输出操作
赶紧弄了0.5版本。修改了碰撞底层的实现。
这个DEMO和上一个DEMO 的区别:
1、从updateWorld里面的碰撞检测看到,这个检测很方便。
2、底层判断已经使用了SAT判断。
3、修改了按键部分的BUG。
4、代码依然很少。
目前引用自制引擎做的DEMO2:
引入了引擎的DEMO代码:
<
ol>
/****************************************************************************
org.ubird.demo.Demo2.java
该类属于JPhysicalEngine游戏引擎中的一部分。JPhysicalEngine游戏引擎
使用Java开发,是一款可以免费学习使用的2D游戏引擎。
*
****************************************************************************
Apache Licence 2.0
****************************************************************************
Copyright 2011 蔡俊鸿
Licensed under the Apache License, Version 2.0 (the “License”);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
****************************************************************************
创建于:2011-4-23
@since JDK1.6
*
****************************************************************************/
package org.ubird.demo;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.ubird.app.SimpleGame;
import org.ubird.collision.CollisionDetector;
import org.ubird.collision.CollisionResult;
import org.ubird.scene.node.ImageNode;
import org.ubird.scene.node.Node;
import org.ubird.scene.particle.ParticleNode;
import org.ubird.scene.particle.ParticleSystem;
import org.ubird.sound.SoundManager;
/**
测试类2
@author junhong.c
@version 1.0
@version 1.1 [2011-05-05] 调整了碰撞检测部分的代码
@version 1.1 [2011-05-05] 增加了按V可以显示物体的轴的功能
@version 1.1 [2011-05-05] 增加了按B可以显示物体的边界的功能
@date 2011-4-23
/
public class Demo2 extends SimpleGame{
private Node player;
private ParticleNode bombParticle = ParticleSystem.getParticles(500,15,15,10);
private ParticleNode hitParticle = ParticleSystem.getParticles(500,15,15,10);
private ImageNode[] bullets = new ImageNode[40];
private int currentBullet = 0;
private long delay; //子弹延时
private boolean fire;
private boolean fire2;
private boolean fire3;
private boolean down;
private boolean up;
private boolean right;
private boolean left;
private Node[] enemys = new ImageNode[7];
private Thread keyProcessThread;
public Demo2() {
super(“Java2D游戏引擎 V0.5.0 — By John.Cha”);
}
public static void main(String[] args) throws IOException {
SimpleGame game = new Demo2();
game.setFPS(60);
game.setStageBackground(“resources/bg.png”);
game.setStageSize(1000,600);
game.start();
}
@Override
public void initWorld() {
initScene();
initNode();
initEvent();
}
/**
事件
/
private void initEvent() {
addKeyListener(new MyKeyListener());
}
/**
定义自己的事件监听
@author junhong.c
@version 1.0
@date 2011-4-22
/
private class MyKeyListener implements KeyListener{
@Override
public void keyTyped(KeyEvent e) {
if(e.getKeyChar()==‘v’){
setDrawAxes(!isDrawAxes());
}
if(e.getKeyChar()==‘b’){
setDrawBounds(!isDrawBounds());
}
}
@Override
public void keyReleased(KeyEvent e) {
switch(e.getKeyCode()){
case KeyEvent.VK_W :
up=false;
break;
case KeyEvent.VK_S:
down=false;
break;
case KeyEvent.VK_D:
right=false;
break;
case KeyEvent.VK_A:
left=false;
break;
case KeyEvent.VK_J:
fire=false;
break;
case KeyEvent.VK_K:
fire2=false;
break;
case KeyEvent.VK_L:
fire3=false;
break;
}
}
@Override
public void keyPressed(KeyEvent e) {
if(fire && e.getKeyCode()==KeyEvent.VK_A) return;
if(fire2 && e.getKeyCode()==KeyEvent.VK_S) return;
if(fire3 && e.getKeyCode()==KeyEvent.VK_D) return;
if(up && e.getKeyCode()==KeyEvent.VK_UP) return;
if(down && e.getKeyCode()==KeyEvent.VK_DOWN) return;
if(left && e.getKeyCode()==KeyEvent.VK_LEFT) return;
if(right && e.getKeyCode()==KeyEvent.VK_RIGHT) return;
switch(e.getKeyCode()){
case KeyEvent.VK_W :
up=true;
break;
case KeyEvent.VK_S:
down=true;
break;
case KeyEvent.VK_D:
right=true;
break;
case KeyEvent.VK_A:
left=true;
break;
case KeyEvent.VK_I:
bombParticle.start(player.getLocation().getIntX()-player.getWidth()/2–3,player.getLocation().getIntY()-player.getHeight());
break;
case KeyEvent.VK_J:
fire=true;
break;
case KeyEvent.VK_K:
fire2=true;
break;
case KeyEvent.VK_L:
fire3=true;
break;
}
if(!getKeyProcessThread().isAlive())
getKeyProcessThread().start();
}
}
/**
场景
/
private void initScene() {
add(bombParticle);
add(hitParticle);
}
/**
处理按键的线程
@return
/
public Thread getKeyProcessThread(){
if(keyProcessThread==null){
keyProcessThread = new Thread(){
public void run(){
try {
while(true){
Thread.sleep(getSPF());
float v = 0.2f;
if(up)
player.getVelocity().setY(-v);
else if(down)
player.getVelocity().setY(v);
if(left)
player.getVelocity().setX(-v);
else if(right)
player.getVelocity().setX(v);
if(!(up||down))
player.getVelocity().setY(0);
if(!(left||right))
player.getVelocity().setX(0);
if( fire ){
if(delay <= System.currentTimeMillis()){
for(int i=0; i<2; i++){
bullets[currentBullet].getVelocity().setY(-v2f);
bullets[currentBullet].getVelocity().setX(0);
int fix = i == 0 ? –15 : 15;
bullets[currentBullet].rotate(0);
float x = player.getLocation().getX()+(player.getWidth() – bullets[currentBullet].getWidth())0.5f;
bullets[currentBullet].setLocation(fix+x, player.getLocation().getY()-bullets[currentBullet].getHeight());
bullets[currentBullet].rotate(0);
currentBullet = ++currentBullet%bullets.length;
SoundManager.play(“resources/sound/bullet.wav”);
}
delay = System.currentTimeMillis()+80;
}
}
if(fire2){
if(delay <= System.currentTimeMillis()){
for(int i=0; i<3; i++){
bullets[currentBullet].getVelocity().setY(-v2f);
int fix = i == 0 ? –15 : i==2 ? 15 : 0;
float vx = i==0 ? -v/4 : i==1 ? 0 : v/4;
bullets[currentBullet].getVelocity().setX(vx);
bullets[currentBullet].rotate(0);
float x = player.getLocation().getX()+(player.getWidth() – bullets[currentBullet].getWidth())0.5f;
bullets[currentBullet].setLocation(fix+x, player.getLocation().getY()-bullets[currentBullet].getHeight());
bullets[currentBullet].rotate(0);
currentBullet = ++currentBullet%bullets.length;
SoundManager.play(“resources/sound/bullet.wav”);
}
delay = System.currentTimeMillis()+100;
}
}
if(fire3){
for(int i=0; i<bullets.length; i++){
bullets[currentBullet].getVelocity().setY(-v2f);
float shita = 6.28fi/(bullets.length-1);
bullets[currentBullet].rotate(shita);
float vx = (float) (vMath.cos(shita));
float vy = (float) (vMath.sin(shita));
bullets[currentBullet].getVelocity().setX(vx);
bullets[currentBullet].getVelocity().setY(vy);
bullets[currentBullet].setLocation(
player.getLocation().getX()+(player.getWidth()-bullets[currentBullet].getWidth())/2,
player.getLocation().getY()+(player.getHeight()-bullets[currentBullet].getHeight())/2);
bullets[currentBullet].setDelay(currentBullet);
currentBullet = ++currentBullet%bullets.length;
}
SoundManager.play(“resources/sound/bomb.wav”);
fire3=false;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
return keyProcessThread;
}
private void initNode() {
try {
Image bulletImage = ImageIO.read(getClass().getClassLoader().getResource(“resources/bullet.png”));
Image planeImage = ImageIO.read(getClass().getClassLoader().getResource(“resources/planes.png”));
/*
初始化子弹
/
for(int i=0; i<bullets.length; i++){
bullets[i] = new ImageNode(bulletImage,0,70,35,35);
bullets[i].setSize(35,35);
bullets[i].setLocation(-500,-500);
bullets[i].setExtent(35/2, 0);
add(bullets[i]);
}
/*
初始化玩家
/
player = new ImageNode(planeImage,100,0,100,120); //平抛–图像结点
player.setSize(60,72);
player.setLocation((getStageWidth()-player.getWidth())/2,getStageHeight()-player.getHeight());
player.setMass(10);
add(player);
/*
初始化敌人
/
for(int i=0; i<enemys.length; i++){
enemys[i] = new ImageNode(planeImage,0,0,100,120);
enemys[i].setSize(60,72);
enemys[i].rotate(6.28fi/(enemys.length-1));
enemys[i].setLocation(i(enemys[i].getWidth()+70),100);
add(enemys[i]);
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
@Override
public void updateWorld(long time) {
player.update(time);
bombParticle.update(time);
hitParticle.update(time);
//更新子弹
for(int i=0; i<bullets.length; i++){
bullets[i].update(time);
}
//更新敌机
for(int i=0; i<enemys.length; i++){
if(enemys[i]!=null){
enemys[i].update(time);
}
}
//子弹和敌机碰撞检测
for(int i=0; i<bullets.length; i++){
if(bullets[i]!=null){
for(int j=0; j<enemys.length; j++){
if(enemys[j]!=null){
CollisionResult cr = CollisionDetector.obb(bullets[i], enemys[j]);
if(cr.isCollision()){
int x = bullets[i].getLocation().getIntX(); //TODO 其实应该是碰撞的位置
int y = bullets[i].getLocation().getIntY(); //TODO 其实应该是碰撞的位置
bullets[i].getLocation().setY(-500);
hitParticle.start(x, y);
}
}
}
<sp