ホームページ | Pirikaで化学 | ブログ | 業務案内 | お問い合わせ |
情報化学+教育トップ | 情報化学 | MAGICIAN | MOOC | プログラミング |
2022.3.3
Pirika.comでプログラミング
山本博志
去年のノーベル賞で、真鍋先生が気候変動のシミュレーションでノーベル賞を取りました。
ですから、炭酸ガス(CO2)が悪者なのは皆さんも知っているでしょう。
では、何故、窒素(N2)や酸素(O2)は悪者ではないのか知っていますか?
空気の中には窒素は78%、酸素(21%)と大量にあるし、二酸化炭素は、たった0.04%しかないのです。
答えは、「炭酸ガスは地球温暖化係数が窒素や酸素よりも何万倍も高いから」。
納得できますか?
これが、理科をつまらなくする最大の理由です。
これでは、何故?に答えたことにはならないのです。
少ない量なのに温暖化に激しく影響を与えているので、窒素や酸素のXXXXX倍って決めたのです。
「何故、勉強のできないの?」って子供に聞いて、「だってテストの点が悪かったんだもの」で納得するか、と同じです。
さー、そこで、真鍋先生がおっしゃっている、”もっと楽しむ姿勢で”、何故かを考えるシミュレーションを考えてみましょう。
真鍋先生が当時使っていたコンピュータは、今のスマホよりも全然遅いものでした。
今なら、とても簡単に試す事ができます。
このプログラムは、次の所から持ってきています。
これを元に、いろいろ改良していきます。
ここではまず綺麗なアニメーションを楽しみましょう。
Startボタンを押して見てください。
空気中の分子、原子はこのように飛び回っています。大きい分子はゆっくり、小さい分子は早く動いています。
壁とぶつかって跳ね返ったり、途中で分子同士がぶつかったりします。
色は全く意味がありません。ランダムにつけています。
ただ、これを気体分子の運動として見ているのは、化学者だけかもしれません。
元々は単なるHTML5のキャンバス利用方法の綺麗なデモです。
壁に衝突して反対側に進むときには、作用・反作用の力が働きます。ボールが反対側に跳ね返るときに、壁にも同じ大きさの反対向きの力が働きます。
この、壁にかかる力をボールごとに全部足してあげると、気体の持っている圧力になります。
低い圧力(低気圧)が来ると天気が悪くなり、高気圧が来ると天気が良くなる、その気(体の)圧(力)です。
次のプログラムをコピペしてBoundingBall.htmlという名前でセーブしましょう。
完成形プログラム(▶︎をクリックして開く)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>跳ね返るボール</title>
</head>
<body>
<h1>bouncing balls</h1>
<canvas width="600" height="350"></canvas>
<input type="button" id="btnStart" value="Start" onclick="StartSimu()">
<script type="text/javascript">
// set up canvas
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const width = canvas.width ;//= window.innerWidth;
const height = canvas.height ;//= window.innerHeight;
let MySimu = false; // シミュレーション・フラグ
// function to generate random number
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// function to generate random RGB color value
function randomRGB() {
return `rgb(${random(0, 255)},${random(0, 255)},${random(0, 255)})`;
}
class Ball {
constructor(x, y, velX, velY, color, size) {
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
}
draw() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.fill();
}
update() {
if ((this.x + this.size) >= width) {
this.velX = -(this.velX);
}
if ((this.x - this.size) <= 0) {
this.velX = -(this.velX);
}
if ((this.y + this.size) >= height) {
this.velY = -(this.velY);
}
if ((this.y - this.size) <= 0) {
this.velY = -(this.velY);
}
this.x += this.velX;
this.y += this.velY;
}
collisionDetect() {
for (const ball of balls) {
if (!(this === ball)) {
const dx = this.x - ball.x;
const dy = this.y - ball.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < this.size + ball.size) {
ball.color = this.color = randomRGB();
}
}
}
}
}
const balls = [];
while (balls.length < 25) {
const size = random(10,20);
const ball = new Ball(
// ball position always drawn at least one ball width
// away from the edge of the canvas, to avoid drawing errors
random(0 + size,width - size),
random(0 + size,height - size),
random(-7,7),
random(-7,7),
randomRGB(),
size
);
balls.push(ball);
}
function loop() {
if(MySimu){
ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
ctx.fillRect(0, 0, width, height);
for (const ball of balls) {
ball.draw();
ball.update();
ball.collisionDetect();
}
requestAnimationFrame(loop);
}
}
// 開始ボタンが押されたとき
function StartSimu() {
if (MySimu) {
MySimu = false;
document.getElementById('btnStart').value = 'シミュレーション開始';
} else {
MySimu = true;
document.getElementById('btnStart').value = 'シミュレーション停止';
loop();
}
}
</script>
</body>
</html>
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
これはR, G, Bの値は0が入っているので黒色です。
全部消してしまうと何も残らないのですが、前の画像に透明度(0.25)で黒く上書きします。
セルをのせるようなイメージです。
そしてボールが移動したところを書く。また黒い半透明のセルをのせる。そうすると、一番下にあるものほど薄くなっていくので残像に見えます。
これが、このプログラムのキモと言うべき面白いテクニックです。
ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
ctx.fillRect(0, 0, width, height);
これは元のプログラムにはありませんでした。
MySimuと言うグローバル変数(プログラムのどこでも使える)を定義します。
そしてこの変数はBoolean型(ブーリアン型は、真理値の「真 = true」と「偽 = false」という2値をとるデータ型)と言う変な変数になります。
Startボタンが押されるたびにtrueとfalseの値が入れ変わります。
trueの時にはシミュレーションが継続し、falseの時には一旦停止します。
if命令の( )の中にはtrueかfalseが入ります。そしてtrueの時には最初の{ }の中が実行され、falseの時には else{ }の中が実行されます。
let MySimu = false; // シミュレーション・フラグ
// 開始ボタンが押されたとき
function StartSimu() {
if (MySimu) {
MySimu = false;
document.getElementById('btnStart').value = 'シミュレーション開始';
//document.getElementById('btnStep').disabled = false;
} else {
MySimu = true;
document.getElementById('btnStart').value = 'シミュレーション停止';
//document.getElementById('btnStep').disabled = true;
loop();
}
このプログラムでは、とても高度なテクニックを使っています。
ここでは25個のボールを扱います。
そして各ボールは、xの位置、yの位置、x方向の速度、y方向の速度、色、大きさの情報を持ちます。
それを一つ一つのボールについて定義して、動作を記述しようとすると大変なことになります。
そこで、ここではボールのクラスというものを定義しています。
これは、ボールのデータと動作をひとまとめにしたものです。
そのひとまとめが25個あるという考え方をします。
class Ball {
constructor(x, y, velX, velY, color, size) {//ボールのデータ
draw() {//ボールを描く
update() {//壁での反射
collisionDetect() {//衝突判定
}
データと機能をカプセル化という高度なプログラムになっています。
各ボールに、ball.draw()という命令を送れば、自分の位置や速度、色、サイズはボール自身がデータとしてわかっているので、勝手に描いてくれます。
壁での反射や衝突判定も各ボールに自分で判定させます。
全部の動きを人間がプログラムしてコントロールするのではなくて、自律的に動いています。
Copyright pirika.com since 1999-
Mail: yamahiroXpirika.com (Xを@に置き換えてください) メールの件名は[pirika]で始めてください。