项目命名: 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] 框架优化、简单的输入输出操作
5.1回家放假了~本来很想继续做,但是一回到家就变懒了T_T,回来后赶紧弄了0.5版本。修改了碰撞底层的实现。
这个DEMO和上一个DEMO 的区别:
1、从updateWorld里面的碰撞检测看到,这个检测很方便。
2、底层判断已经使用了SAT判断。
3、修改了按键部分的BUG。
4、增加了场景多层背景的支持
5、代码依然很少。
目前引用自制引擎做的DEMO2:
引入了引擎的DEMO代码:
- /****************************************************************************
- * 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(-v*2f);
- 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(-v*2f);
- 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(-v*2f);
- float shita = 6.28f*i/(bullets.length-1);
- bullets[currentBullet].rotate(shita);
- float vx = (float) (v*Math.cos(shita));
- float vy = (float) (v*Math.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.28f*i/(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);
- }
- }
- }
- }
- }
- }
- }