zoukankan      html  css  js  c++  java
  • 设置位置在JavaFX中使用物理引擎JBox2D

    本文纯属个人见解,是对前面习学的总结,如有描述不正确的地方还请高手指正~

        周末然突想到了,游戏引擎里自然是要需一个物理引擎的,于是究研了一下JBox2D(至于为什么是JBox2D,也只是因为认为JBox2D的可移植性更好,是不是采取其他的物理引擎等后以再说)。

          由于本人开辟的JavaFX的游戏引擎WJFXGame现在在赶工中,里头的物理引擎的例子发出来也不容易习学。所以我又从新写了个。

          其实很单简,JBox2D的物理作操和图形渲染是离开的,我们只要需担任理处图形渲染的分部可即。

        

        

          示例地址:  点击

          

          我们在这里用使的是官网下载的最新版的JBox2D,如下图所示:

          

        

          首先,我们建新一个JBox2D中的刚体与JavaFX里头的图形结合的一个类WBody。

          

    import javafx.scene.canvas.GraphicsContext;
    import javafx.scene.paint.Paint;
    
    import org.jbox2d.dynamics.Body;
    public abstract class WBody{
        protected Body mBody;
        protected Paint mColor;
        protected final static int RATE = 30;
        protected double x,y,width,height;
    	public Body getBody() {
    		return mBody;
    	}
    	public void setBody(Body mBody) {
    		this.mBody = mBody;
    	}
    	public Paint getColor() {
    		return mColor;
    	}
    	public void setColor(Paint mColor) {
    		this.mColor = mColor;
    	}
    	
    	public abstract void draw(GraphicsContext gc);
    	
    	public abstract void update();
    	
    	public double getX() {
    		return x;
    	}
    	public void setX(double x) {
    		this.x = x;
    	}
    	public double getY() {
    		return y;
    	}
    	public void setY(double y) {
    		this.y = y;
    	}
    	
    	public void setLocation(double x,double y){
    		setX(x);
    		setY(y);
    	}
    	public double getWidth() {
    		return width;
    	}
    	public void setWidth(double width) {
    		this.width = width;
    	}
    	public double getHeight() {
    		return height;
    	}
    	public void setHeight(double height) {
    		this.height = height;
    	}
    	
    }

      

          这个类中,包含了一个刚体body,和一系列位置小大等属性的设置。为了单简,这里都是用的通普的属性,没有用使可绑定的属性(在WJFXGame中,我都是用使的JavaFX的可绑定的属性)。

          RATE是屏幕与天下的比例。平日这个比例越大,由于重力速度雷同,在屏幕里看到的会运动的更快。

          

          然后我们创立一个圆的WBody,叫WCircleBody。

          

    import org.jbox2d.dynamics.Body;
    
    import javafx.beans.property.DoubleProperty;
    import javafx.beans.property.SimpleDoubleProperty;
    import javafx.scene.canvas.GraphicsContext;
    import javafx.scene.paint.Paint;
    
    public class WCircleBody extends WBody {
    
    	protected DoubleProperty radius;
    	
    	public WCircleBody(Body body, double radius, Paint color){
    		this.mBody = body;
    		this.radius = new SimpleDoubleProperty(radius);
    		this.mColor = color;
    	}
    	
    	@Override
    	public void draw(GraphicsContext gc) {
    		gc.save();
    		gc.setFill(mColor);
    		gc.fillOval(getX(), getY(),  getRaidus() * 2, getRaidus() * 2);
    		gc.restore();
    	}
    
    	@Override
    	public void update() {
    		setX(mBody.getPosition().x * RATE - getRaidus());
    		setY(mBody.getPosition().y * RATE - getRaidus());
    	}
    	
    	public double getWidth(){
    		return 2 * getRaidus();
    	}
    	
    	public double getHeight(){
    		return 2 * getRaidus();
    	}
    
    	public DoubleProperty radiusProperty(){
    		return radius;
    	}
    	
    	public double getRaidus(){
    		return radius.get();
    	}
    	
    	public void setRadius(double radius){
    		this.radius.set(radius);
    	}
    }

          这个承继于WBody,draw方法中根据x,y和半径,来制绘圆。在update方法中,将圆的图形位置设置为Body刚体的位置。由于刚体里的position是正心中的,所以我们要需自己停止盘算左上角的位置。

          

          然后创立一个矩形的WBody,叫WBoxBody。

          

    import javafx.scene.canvas.GraphicsContext;
    import javafx.scene.paint.Paint;
    
    import org.jbox2d.dynamics.Body;
    
    public class WBoxBody extends WBody {
    	public WBoxBody(double width,double height, Body body, Paint paint) {
    		this.mBody = body;
    		this.mColor = paint;
    		this.width = width;
    		this.height = height;
    	}
    
    	@Override
    	public void draw(GraphicsContext gc) {
    		gc.save();
    		gc.setFill(mColor);
    		gc.fillRect(getX(), getY(), getWidth(),getHeight());
    		gc.restore();
    	}
    
    	@Override
    	public void update() {
            setX(mBody.getPosition().x * RATE - getWidth() / 2);
            setY(mBody.getPosition().y * RATE - getHeight() / 2);
    	}
    
    }

       样同的,WBoxBody里跟WCircleBody里似类。就不做过多解释了。

          

           面下我们来建新一个类承继Canvas,来担任全部的制绘和新更作操。

          

        每日一道理
    生命不是一篇"文摘",不接受平淡,只收藏精彩。她是一个完整的过程,是一个"连载",无论成功还是失败,她都不会在你背后留有空白;生命也不是一次彩排,走得不好还可以从头再来,她绝不给你第二次机会,走过去就法无回头。
    import java.util.List;
    import java.util.concurrent.CopyOnWriteArrayList;
    
    import javafx.animation.KeyFrame;
    import javafx.animation.Timeline;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.canvas.Canvas;
    import javafx.scene.canvas.GraphicsContext;
    import javafx.scene.paint.Color;
    import javafx.util.Duration;
    
    import org.jbox2d.collision.AABB;
    import org.jbox2d.collision.shapes.CircleShape;
    import org.jbox2d.collision.shapes.PolygonShape;
    import org.jbox2d.common.Vec2;
    import org.jbox2d.dynamics.Body;
    import org.jbox2d.dynamics.BodyDef;
    import org.jbox2d.dynamics.BodyType;
    import org.jbox2d.dynamics.FixtureDef;
    import org.jbox2d.dynamics.World;
    import org.wing.jfx.physics.test.body.WBody;
    import org.wing.jfx.physics.test.body.WBoxBody;
    import org.wing.jfx.physics.test.body.WCircleBody;
    
    public class CanvasScreen extends Canvas {
    	private GraphicsContext gc;
    	private Timeline mTimeline;
    	private double duration = 10;
    	private static final int RATE = 10;
    	private World world;
    	private AABB aabb;
    	private BodyDef bd;
    
        private List<WBody> bodys = new CopyOnWriteArrayList<>();
    	public CanvasScreen(double width, double height) {
    		super(width, height);
    
    		Vec2 gravity = new Vec2(-1.0f, 10.0f);
    		world = new World(gravity);
    
    		Vec2 minV = new Vec2(-100.0f, -100.0f);
    		Vec2 maxV = new Vec2(100.0f, 100.0f);
    
    		aabb = new AABB();
    		aabb.lowerBound.set(minV);
    		aabb.upperBound.set(maxV);
    
    		world.queryAABB(null, aabb);
    		bd = new BodyDef();
    
    		gc = getGraphicsContext2D();
    		init();
    		initObjects();
    	}
    
    	public void init() {
    		mTimeline = new Timeline();
    		mTimeline.setCycleCount(Timeline.INDEFINITE);
    		KeyFrame frame = new KeyFrame(Duration.millis(duration), new EventHandler<ActionEvent>() {
    
    			@Override
    			public void handle(ActionEvent event) {
    				draw(gc);
    				update();
    
    			}
    		});
    		mTimeline.getKeyFrames().add(frame);
    		mTimeline.play();
    	}
    
    	public void initObjects(){
    		createPolygon(10, 500, (int) getWidth() - 10 * 2, 10, 0.3f, 0.6f, true);
    		createPolygon(10, 10, 10, 500, 0.3f, 0.6f, true);
    		createPolygon((int) getWidth() - 10 * 2, 10, 10, 500, 0.3f, 0.6f, true);
    		float restitution[] = new float[] { 0.9f, 0.9f, 0.9f, 0.9f, 0.75f, 0.9f, 1.0f, 0.6f, 0.8f, 0.4f, 0.9f, 0.9f,
    				0.9f, 0.9f, 0.75f, 0.9f, 1.0f, 0.6f, 0.8f, 0.4f, 0.9f, 0.9f, 0.9f, 0.9f, 0.75f, 0.9f, 1.0f, 0.6f, 0.8f,
    				0.4f, 0.9f, 0.9f, 0.9f, };
    		for (int i = 0; i < restitution.length; i++) {
    			createCircle(80 + i * 20, 5 * i, 15, 0.3f, restitution[i], false);
    		}
    	}
    	
    	public void draw(GraphicsContext gc) {
    		gc.clearRect(0, 0, getWidth(), getHeight());
    	    gc.setFill(Color.BLACK);
    	    gc.fillRect(0, 0, getWidth(), getHeight());
    		for(WBody mBody : bodys){
    			mBody.draw(gc);
    		}
    	}
    
    	public void update() {
    		for(WBody body : bodys){
    			body.update();
    		}
    		
    		world.step(1.0f / 60.0f, 8, 3);
    	}
    
    	/**
    	 * 创立矩形
    	 */
    	public void createPolygon(float x, float y, float w, float h, float friction, float restitution, boolean isStatic) {
    		// 创立多边形皮肤
    		PolygonShape shape = new PolygonShape();
    		shape.setAsBox(w / 2 / RATE, h / 2 / RATE);
    
    		FixtureDef fd = new FixtureDef();
    		fd.shape = shape;
    		fd.density = 1.0f; // 设置密度
    		fd.friction = friction; // 设置摩擦力
    		fd.restitution = restitution; // 设置多边形的恢复力
    
    		// 设置刚体初始坐标
    		bd.type = isStatic ? BodyType.STATIC : BodyType.DYNAMIC;
    		bd.position.set((x + w / 2) / RATE, (y + h / 2) / RATE);
    
    		// 创立物体
    		Body body = world.createBody(bd); // 物理天下创立物体
    
    		// 此方法改变了
    		// body.createShape(pDef); //为body添加皮肤
    		body.createFixture(fd);
    
    		WBoxBody boxBody = new WBoxBody(w, h, body, Color.WHITE);
    		boxBody.setLocation(x, y);
    		bodys.add(boxBody);
    	}
    
    	/**
    	 * 创立圆形
         */
    	public void createCircle(float x, float y, float r, float friction, float restitution, boolean isStatic) {
    		CircleShape shape = new CircleShape();
    		shape.m_radius = r / RATE;
    
    		FixtureDef fd = new FixtureDef();
    		fd.shape = shape;
    		fd.density = 1.0f;
    		fd.friction = friction;
    		fd.restitution = restitution;
    
    		// 创立刚体
    		bd.type = isStatic ? BodyType.STATIC : BodyType.DYNAMIC;
    		bd.position.set((x + r) / RATE, (y + r) / RATE);
    
    		// 创立一个body
    		Body body = world.createBody(bd);
    		body.createFixture(fd);
    
    		WCircleBody circleBody = new WCircleBody(body, r, Color.RED);
    		circleBody.setLocation(x, y);
    		bodys.add(circleBody);
    	}
    }

      

          在这个CanvasScreen里,重要做了以下几个作操。

          1.创立了JBox2D的天下World

          2.创立了一个Timeline,增加了一个Keyframe,通过无限循环来模拟游戏的新更作操。

          3.通过createPolygon和createCircle来创立Body并初始化WBody素元。这里要需注意Body的position为心中位置,而我们制绘的Object是以左上为position,要需自行理处一下。还有就是屏幕与天下的比例RATE,在停止position的时候的理处。

          4.在keyframe中,制绘WBody表列并在update中新更WBody表列。

          5.新更World,我们在update中world.step(...)停止新更JBox的World里的物理变化。如果没有world.step,全部的物理作操将法无停止。

        

          接下来是我们的主类。

          

    import javafx.application.Application;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    
    public class MainClass extends Application {
    	private static final int WIDTH = 800;
    	private static final int HEIGHT = 600;
    
    	@Override
    	public void start(Stage primaryStage) {
    		CanvasScreen mCanvas = new CanvasScreen(WIDTH, HEIGHT);
    		Group root = new Group();
    		root.getChildren().add(mCanvas);
    		Scene scene = new Scene(root, WIDTH, HEIGHT);
    
    		primaryStage.setTitle("JavaFX中JBox2D的用使");
    		primaryStage.setScene(scene);
    		primaryStage.show();
    	}
    
    	public static void main(String[] args) {
    		launch(args);
    	}
    }

          大家可以看看行运果效。

          点击

        

          本人用使的是JDK7,大家看示提下载吧。

          果效图:

          

        

    文章结束给大家分享下程序员的一些笑话语录: 据说有一位软件工程师,一位硬件工程师和一位项目经理同坐车参加研讨会。不幸在从盘山公路下山时坏在半路上了。于是两位工程师和一位经理就如何修车的问题展开了讨论。
    硬件工程师说:“我可以用随身携带的瑞士军刀把车坏的部分拆下来,找出原因,排除故障。”
    项目经理说:“根据经营管理学,应该召开会议,根据问题现状写出需求报告,制订计划,编写日程安排,逐步逼近,alpha测试,beta1测试和beta2测试解决问题。”
    软件工程说:“咱们还是应该把车推回山顶再开下来,看看问题是否重复发生。”

  • 相关阅读:
    机器学习笔记之K近邻算法
    [C++基础]在子类中向父类的构造函数传递参数的小例子,包括类中常量的初始化
    POJ2709 染料贪心
    POJ2337 欧拉路径字典序输出
    POJ2337 欧拉路径字典序输出
    POJ1042 贪心钓鱼
    POJ3228二分最大流
    POJ3228二分最大流
    POJ3498最大流,枚举终点,企鹅,基础最大流
    POJ3498最大流,枚举终点,企鹅,基础最大流
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3036013.html
Copyright © 2011-2022 走看看