前言

最近学习了《代码本色》这本书,本书介绍了用计算机模拟自然系统涉及的编程策略与技术,涵盖了基本的数学和物理概念,以及可视化地展示模拟结果所需的高级算法。读者将从构建基本的物理引擎开始,一步一步地学习如何创建智能移动的物体和复杂的系统,为进一步探索生成设计奠定基础。相关的知识点包括力、三角、分形、细胞自动机、自组织和遗传算法。

看完之后,了解到可以使用一行行的代码来模拟这个复杂的世界,深受触动,感受颇深,在此编写了一个小游戏,来学习书中的技术。

游戏展示

《代码本色》学习练习——加农炮小游戏展示
游戏非常简单,使用方向键来控制加农炮的移动和瞄准,使用空格键来蓄力发射,其中小球的运动及与墙壁和地面的碰撞用到了书中向量与力的知识,小球射出三秒之后会爆炸四散,运用了书中粒子效果的知识。

关键技术

首先为了使炮弹能够进行物理运动,需要为其赋予位置、速度、加速度、质量等值:

class Ball {
    constructor(x, y, radius, mass) {
        this.loc = createVector(x, y);
        this.radius = radius;
        this.mass = mass;

        this.acc = createVector(0, 0);
        this.vel = createVector(0, 0);

        this.frame = 0;
    	}
    }

其中frame的值用来记录炮弹存在的帧数,每次画面更新会使该计数+1。

其次是为所有射出的炮弹施加空气阻力和重力:

function draw() {
    for (let i = 0; i < usedBall.length; i++) {
        if (usedBall[i].outside) {
            //apply air resistance
            let force = usedBall[i].vel.copy();
            force.normalize();
            let v = usedBall[i].vel.mag();
            force.mult(-0.1 * v);
            usedBall[i].applyForce(force);

            //apply gravity
            usedBall[i].applyForce(gravity);
 		}
 	}
}

利用炮弹中心位置、半径和边界位置来实现碰撞检测,并根据碰撞的位置将相应的x速度或y速度取反:

checkCollision(x, y, w, h) {
    // hit edges
    if (this.loc.x - this.radius <= 0 || this.loc.x + this.radius >= width) {
        this.vel.x *= -1;
    }

    //hit ground
    if (this.loc.x >= x && this.loc.x <= x + w) {
        if (this.loc.y + this.radius >= y) {
            this.loc.y = y - this.radius;
            this.vel.y *= -0.9;
        }
    }
    if (this.loc.x - x - w <= this.radius) {
        if (this.loc.y > y) {
            this.vel.x *= -1;
        }
    }
}

最后,当炮弹爆炸时,在炮弹的当前位置产生一个粒子系统来实现爆炸效果:

if (usedBall[i].isDead()) {
    for (var c = 0; c < 20; c++) {
        explodedBall.push(new Explosion(createVector(usedBall[i].loc.x, usedBall[i].loc.y)));
    }
    usedBall.splice(i, 1);
}

相关文章: