【问题标题】:Creating water with p5.js使用 p5.js 创建水
【发布时间】:2018-07-04 20:35:12
【问题描述】:

我正在尝试在 p5.js 中使用波浪和所有内容创建一些水效果,但我似乎无法让水中的波浪起作用。我正在从 Michael Hoffman 的 this 文章中掀起波澜。我为水创建了两个类,一个名为“Springs”的类,它模拟了水的弹簧效果,一个名为“Liquid”的类,它只保存了一个弹簧列表和一些常量。

为了显示水,我使用 p5 的 beginShape() 和 vertex() 函数来创建水面。我经历并创建了每个弹簧高度的顶点。

现在的水是静止的。我希望水只有在球撞击水面时才会产生波浪。我已将 Liquid 的“contains”方法设置为 true,以查看 wave 是否正常工作。

我想知道我画水的方式是否有问题。以前,当我单击时会出现类似弹簧的效果,除了整个水面将保持为矩形。使用矢量在水中产生波浪有什么问题吗?与霍夫曼建议的那样绘制梯形相比,创建波浪似乎是一种更简单的解决方案,但事实证明我可以使用 p5.js 轻松绘制梯形。

感谢您的帮助。

代码如下:

var balls = [];

var liquid; 

function Liquid(s) {
    this.springs = s;
    this.tension = 0.025;
    this.dampening = 0.025;
    this.spread = 0.25;
}

function Spring() {
    this.targetHeight = 0;
    this.height = 0;
    this.vel = 0;

    this.update = function(dampening, tension) {
        let x = this.targetHeight - this.height;
        this.vel += (tension * x - this.vel * dampening);
        this.height += this.vel;
    }
}

Liquid.prototype.update = function () {

    for (var i = 0; i < this.springs.length; i++)
        this.springs[i].update(this.dampening, this.tension);

    var lDeltas = [];
    var rDeltas = [];

    // do some passes where columns pull on their neighbours
    for (var j = 0; j < 8; j++)
    {
        for (var i = 0; i < this.springs.length; i++)
        {
            if (i > 0)
            {
                lDeltas[i] = this.spread * (this.springs[i].height - this.springs[i - 1].height);
                this.springs[i - 1].vel += lDeltas[i];
            }
            if (i < this.springs.length - 1)
            {
                rDeltas[i] = this.spread * (this.springs[i].height - this.springs[i + 1].height);
                this.springs[i + 1].vel += rDeltas[i];
            }
        }

        for (var i = 0; i < this.springs.length; i++)
        {
            if (i > 0)
                this.springs[i - 1].height += lDeltas[i];
            if (i < this.springs.length - 1)
                this.springs[i + 1].height += rDeltas[i];
        }
    }
}

Liquid.prototype.splash = function (index, speed) {
    if (index >= 0 && index < this.springs.length)
        this.springs[i].vel = speed;
}

Liquid.prototype.display = function () {
    fill(0, 0, 255);
    beginShape();
    vertex(0, height - this.springs[0].height);
    for (var i = 0; i < this.springs.length; i++) {
        vertex(i * (width / this.springs.length), height-this.springs[i].height); //consider using the map function
    }
    vertex(width, height);
    vertex(0, height);
    endShape(CLOSE);
}

Liquid.prototype.contains = function(m) {
    return true;
};

function Mover(m, x, y) {
    this.mass = m;
    this.position = createVector(x,y);
    this.velocity = createVector(0,0);
    this.acceleration = createVector(0,0);
}

// f = m / a --> a = f / m

Mover.prototype.applyForce = function(force) {
    var f = p5.Vector.div(force,this.mass);
    this.acceleration.add(f);
}

Mover.prototype.update = function() {
    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);
    this.acceleration.mult(0); //acceleration must be cleared; does not add to itself!
};

Mover.prototype.display = function() {
    stroke(0); //black outline
    strokeWeight(2); //make it more visible
    fill(255,127); //give it a gray color
    ellipse(this.position.x,this.position.y,this.mass*16,this.mass*16); //create an ellipse at the position
};

function setup() {
    createCanvas(windowWidth, windowHeight);
    background(255);
    var temp = [];
    for (var i = 0; i < 340; i++) { //340 is an arbitrary num
        var tempSpring = new this.Spring();
        tempSpring.targetHeight = height/2;
        tempSpring.height = height/2;
        temp[i] = tempSpring;
    }
    liquid = new Liquid(temp);
    liquid.display();
}

function draw() {
    background(255);
    for (var i = 0; i < balls.length; i++) {

        if(liquid.contains(balls[i])) {
            liquid.splash(balls[i].x, 0.05);
        }
        liquid.update();
        liquid.display();
        // Gravity is scaled by mass here!
        var gravity = createVector(0, 0.1*balls[i].mass);
        // Apply gravity
        balls[i].applyForce(gravity);
        balls[i].update();
        balls[i].display();


    }
    liquid.display();
}

function mousePressed() {
    balls[balls.length] = new Mover(5, mouseX, mouseY);
}

【问题讨论】:

  • 开始减少你的代码。简单地移除所有交互部分(球、点击等),并在第 1 帧触发弹簧的状态下开始您的草图。然后开始检查您留下的代码,以查看数据是否真的在帧之间发生变化,通过跟踪您设置的函数调用。 lDeltas 和 rDeltas 会改变吗?如果没有,请开始查看应该导致它们发生变化的变量:它们是否在变化?如果没有,看看应该改变什么那些他们在改变吗?如果没有,等等。
  • 我同意迈克的观点。您需要 break your problem down into smaller steps 然后发布 minimal reproducible example 显示特定步骤。祝你好运。

标签: javascript html game-physics p5.js


【解决方案1】:

从哪里开始:

  • 没有 balls[i].x 这样的东西。
  • splash() 中未定义变量“i”。
  • 您正在使用球的 x 坐标来索引 springs 数组(在 splash() 中),这似乎不正确。首先,x 坐标的范围是 0 到 width,springs 数组索引的范围是 0 到 339。其次,x 坐标是一个非整数值,所以用它来索引数组是行不通的。
  • 球总是溅水
  • 水不作用于球

找到这些东西的唯一最佳方法是学习如何在浏览器中使用调试器,逐行检查代码,检查所有内容并确保它们符合您的预期。大多数这些简单的错误都会立即跳出来。

var balls = [];

var liquid;

function Liquid(s) {
  this.springs = s;
  this.tension = 0.025;
  this.dampening = 0.025;
  this.spread = 0.25;
}

function Spring() {
  this.targetHeight = 0;
  this.height = 0;
  this.vel = 0;

  this.update = function(dampening, tension) {
    let x = this.targetHeight - this.height;
    this.vel += tension * x - this.vel * dampening;
    this.height += this.vel;
  };
}

Liquid.prototype.update = function() {
  for (var i = 0; i < this.springs.length; i++)
    this.springs[i].update(this.dampening, this.tension);

  var lDeltas = [];
  var rDeltas = [];

  // do some passes where columns pull on their neighbours
  for (var j = 0; j < 8; j++) {
    for (var i = 0; i < this.springs.length; i++) {
      if (i > 0) {
        lDeltas[i] =
          this.spread * (this.springs[i].height - this.springs[i - 1].height);
        this.springs[i - 1].vel += lDeltas[i];
      }
      if (i < this.springs.length - 1) {
        rDeltas[i] =
          this.spread * (this.springs[i].height - this.springs[i + 1].height);
        this.springs[i + 1].vel += rDeltas[i];
      }
    }

    for (var i = 0; i < this.springs.length; i++) {
      if (i > 0) this.springs[i - 1].height += lDeltas[i];
      if (i < this.springs.length - 1) this.springs[i + 1].height += rDeltas[i];
    }
  }
};

Liquid.prototype.splash = function(index, speed) {
  if (index >= 0 && index < this.springs.length) this.springs[floor(index)].vel = speed;
};

Liquid.prototype.display = function() {
  fill(0, 0, 255);
  beginShape();
  vertex(0, height - this.springs[0].height);
  for (var i = 0; i < this.springs.length; i++) {
    vertex(i * (width / this.springs.length), height - this.springs[i].height); //consider using the map function
  }
  vertex(width, height);
  vertex(0, height);
  endShape(CLOSE);
};

Liquid.prototype.contains = function(m) {
  return true;
};

function Mover(m, x, y) {
  this.mass = m;
  this.position = createVector(x, y);
  this.velocity = createVector(0, 0);
  this.acceleration = createVector(0, 0);
}

// f = m / a --> a = f / m

Mover.prototype.applyForce = function(force) {
  var f = p5.Vector.div(force, this.mass);
  this.acceleration.add(f);
};

Mover.prototype.update = function() {
  this.velocity.add(this.acceleration);
  this.position.add(this.velocity);
  this.acceleration.mult(0); //acceleration must be cleared; does not add to itself!
};

Mover.prototype.display = function() {
  stroke(0); //black outline
  strokeWeight(2); //make it more visible
  fill(255, 127); //give it a gray color
  ellipse(this.position.x, this.position.y, this.mass * 16, this.mass * 16); //create an ellipse at the position
};

function setup() {
  createCanvas(windowWidth, windowHeight);
  background(255);
  var temp = [];
  for (var i = 0; i < 340; i++) {
    //340 is an arbitrary num
    var tempSpring = new Spring();
    tempSpring.targetHeight = height / 2;
    tempSpring.height = height / 2;
    temp[i] = tempSpring;
  }
  liquid = new Liquid(temp);
  liquid.display();
}

function draw() {
  background(255);
  liquid.update();
  liquid.display();

  for (var i = 0; i < balls.length; i++) {
    var ball = balls[i];

    if (liquid.contains(ball)) {
      liquid.splash(ball.position.x, 54.5);
    }
    //liquid.display();
    // Gravity is scaled by mass here!
    var gravity = createVector(0, 0.1 * ball.mass);
    // Apply gravity
    ball.applyForce(gravity);
    ball.update();
    ball.display();
  }
}

function mousePressed() {
  balls[balls.length] = new Mover(5, mouseX, mouseY);
}
html,
body {
  margin: 0;
  padding: 0;
  border: none;
  background: black;
}
canvas {
  display: block;
}
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.js"&gt;&lt;/script&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-29
    • 1970-01-01
    • 1970-01-01
    • 2020-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多