草庐IT

java - 有效地绘制大量粒子

coder 2024-03-28 原文

我写了一个粒子系统小程序;目前我正在创建并分别绘制每个粒子。 (这里是代码)

BufferedImage backbuffer;
Graphics2D g2d;

public void init(){
    backbuffer = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB);
    g2d = backbuffer.createGraphics();
    setSize(WIDTH, HEIGHT);

    //creates the particles
    for (int i = 0; i < AMOUNTPARTICLES; i++) {
        prtl[i] = new particleO();
        prtl[i].setX(rand.nextInt(STARTX));
        prtl[i].setY(rand.nextInt(STARTY));
        prtl[i].setVel(rand.nextInt(MAXSPEED)+1);
        prtl[i].setFAngle(Math.toRadians(rand.nextInt(ANGLESPREAD)));

        }

    //other code
}



    public void update(Graphics g) {        

    g2d.setTransform(identity);

    //set background
    g2d.setPaint(BGCOLOUR);
    g2d.fillRect(0,0,getSize().width,getSize().height);
    drawp();
    paint(g);           
    }


public void drawp() {

    for (int n = 0; n < AMOUNTPARTICLES; n++) {

    if (prtl[n].getAlive()==true){
            g2d.setTransform(identity);
            g2d.translate(prtl[n].getX(), prtl[n].getY());
            g2d.setColor(prtl[n].getColor());

            g2d.fill(prtl[n].getShape());


            }
    }

}

它的性能还不错,我可以用 20,000 个粒子获得大约 40FPS(尽管我有一台不错的笔记本电脑)。但是在我添加了碰撞检测之后(见下文),这个数字直线下降到不到 2000,

public void particleUpdate(){
 for (int i = 0; i < AMOUNTPARTICLES; i++) {
        //other update code (posx, posy, angle etc etc)

          for (int j = 0; j < AMOUNTPARTICLES; j++) {

                if (i!=j && prtl[j].getAlive()==true){

                     if(hasCollided(i, j)){
                        prtl[i].setcolor(Color.BLACK);
                        prtl[j].setcolor(Color.BLACK);
     }
            }
  }

public boolean hasCollided(int prt1, int prt2){

        double dx = prtl[prt1].getX() - prtl[prt2].getX();
        double dy = prtl[prt1].getY() - prtl[prt2].getY();
        int edges =  prtl[prt1].getRadius() + prtl[prt2].getRadius();

        double distance = Math.sqrt( (dx*dx) + (dy*dy) );
        return (distance <= edges);


    }

我已经搜索了很多将粒子绘制到屏幕上的更好方法,但这些示例要么让我感到困惑,要么不适用。

我正在进行大量计算(太多)。但我想不出其他方法,欢迎提出建议。

最佳答案

首先,添加诸如碰撞检测之类的东西总是需要大量内存。但是,让我们看看您的碰撞检测算法

public void particleUpdate(){
 for (int i = 0; i < AMOUNTPARTICLES; i++) {
        //other update code (posx, posy, angle etc etc)

          for (int j = 0; j < AMOUNTPARTICLES; j++) {

                if (i!=j && prtl[j].getAlive()==true){

                     if(hasCollided(i, j)){
                        prtl[i].setcolor(Color.BLACK);
                        prtl[j].setcolor(Color.BLACK);
                }
            }
  }

假设只有 2 个粒子,1 和 2。您将按顺序检查 1,1 1,2 2,1 2,2

事实是,在这种情况下,您真的只需要检查 1 对 2。如果 1 击中 2,则 2 也将击中 1。因此请更改之前测试过的 for 循环跳过,并为此更改相同的数字。

public void particleUpdate(){
 for (int i = 0; i < AMOUNTPARTICLES; i++) {
        //other update code (posx, posy, angle etc etc)

          for (int j = i+1; j < AMOUNTPARTICLES; j++) {

我注意到的另一件事是您进行了 sqrt 操作,但只是为了与看起来像静态数字的内容进行比较。如果你删除它,并将它与数字的平方进行比较,你会得到很大的改进,尤其是对于你经常做的事情。

    double distance_squared = ( (dx*dx) + (dy*dy) );
    return (distance <= edges*edges);

继续寻找这样的改进。然后您可能会仔细查看其他选项,例如使用不同的类、线程等,这些都可能会改进系统。但是请确保先在可以优化的地方优化代码。这是我会尝试的其他事情的列表,大致按顺序排列。

  1. 在 i 进入视野后计算任何其他东西之前,先检查一下粒子 i 是否还活着。
  2. 快速浏览两对,如果它们很接近,甚至不会费心去详细检查。一种简单的方法是先检测它们是否在 x 和 y 维度内,然后再进行 sqrt 操作。始终先进行成本最低的测试,然后再进行复杂的测试。
  3. 查看您的代码,看看您是否真的使用了所有计算出的值,或者您是否能够以某种方式减少操作次数。
  4. 也许您可以定期对图像进行粗略的聚类,然后仅细化通过初始聚类一段时间的对象,然后执行粗略的聚类算法。
  5. 您可以线程化碰撞检测。但是,如果您打算这样做,您应该只对检查进行线程化以查看是否发生了碰撞,并在所有这些线程完成后,更新 View 上的对象。
  6. 研究替代架构,这可能会加快速度。

关于java - 有效地绘制大量粒子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13521368/

有关java - 有效地绘制大量粒子的更多相关文章

  1. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  2. ruby - 如何进行排列以有效地定制输出 - 2

    这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

  3. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  4. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  5. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  6. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  7. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  8. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  9. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  10. python - 是否可以使用 Ruby 或 Python 禁用 anchor /引用来发出有效的 YAML? - 2

    是否可以在PyYAML或Ruby的Psych引擎中禁用创建anchor和引用(并有效地显式列出冗余数据)?也许我在网上搜索时遗漏了一些东西,但在Psych中似乎没有太多可用的选项,而且我也无法确定PyYAML是否允许这样做.基本原理是我必须序列化一些数据并将其以可读的形式传递给一个不是真正的技术同事进行手动验证。有些数据是多余的,但我需要以最明确的方式列出它们以提高可读性(anchor和引用是提高效率的好概念,但不是人类可读性)。Ruby和Python是我选择的工具,但如果有其他一些相当简单的方法来“展开”YAML文档,它可能就可以了。 最佳答案

随机推荐