知らないことを調べるブログ

映画の分からないところを調べてまとめる場所にしていきます。

くるくる回るおもちゃ(HTML5+JavaScript、java)

 くるくる回るおもちゃを作った。HTML5+JavaScript
 
 四角形の中心にマウスを近づけるとだんだん加速。離れると減速。止まっているあいだは再描画しない。
 
 
 参考にした記事。プログラミング学習サイト「コードレシピ」を管理しているおっ立ち野郎さんって、前にスターをくれた人だ。「コードレシピ」から、テトリスぷよぷよとラングトンのアリとライフゲームを写経した。楽しかった。
 
coderecipe.jp
jmqys.hatenablog.com
d.hatena.ne.jp
 
 
 くるくる回るおもちゃのソースコード。50行くらい。

<canvas id="world"width="320" height="320"></canvas>
<script type="text/javascript">

/* グローバル変数の宣言 */
var SCREEN_SIZE = 282; // キャンバスの幅
var FPS = 60; // フレームレート
var canvas; //= document.getElementById('world');
var context; //= canvas.getContext('2d');
var x;
var y;
var angle = 0; // 角度
var distance; // おもちゃの中心までの距離
var speed; // 速度
var acceleration; // 加速度
var RESISTANCE = 0.05; // 空気抵抗

function start() {
  /* ゲームの初期化処理と開始処理 */
  canvas = document.getElementById('world'); // canvas要素を取得
  canvas.width = canvas.height = SCREEN_SIZE; // キャンバスのサイズを設定
  context = canvas.getContext('2d');                // コンテキスト
  context.fillStyle = 'rgb(0, 0, 0)';          // 色
  draw();
  update();   // ゲームループ開始
}

function update() { // 距離の計測とキャンバスの描画処理
  canvas.onmousemove = function(event) { // マウスの座標を得る
    x = event.offsetX;
    y = event.offsetY;
  }
  distance = Math.sqrt((SCREEN_SIZE / 2 - x) * (SCREEN_SIZE / 2 - x) + (SCREEN_SIZE / 2 - y) * (SCREEN_SIZE / 2 - y)); // 2点間の距離を計算
  if(angle > 90) angle -= 90;
    acceleration = 0.1 - (distance / 1000); // 0.1は最高速度。おもちゃの中心からマウスが離れると減算される
    if(acceleration > 0) speed += acceleration; // 加速度が0以上なら加速
    speed -= RESISTANCE; // おもちゃの回転は常に空気抵抗を受ける
    if(speed >= 0) angle += speed; else speed = 0; // 速度が0以上なら加速。マイナスなら0
  if(speed != 0) draw(); // canvasを更新
  setTimeout(update, 1000/FPS); // ミリ秒後に再帰
}

function draw() { // キャンバスの描画処理。update関数で呼び出される
  context.save(); // 描画スタイルを保存
  context.clearRect(0, 0, SCREEN_SIZE, SCREEN_SIZE); // 画面をクリア
  context.translate(SCREEN_SIZE / 2, SCREEN_SIZE / 2);
  context.rotate(angle * Math.PI / 180); // おもちゃを回転
  context.fillRect(-100, -100, 200, 200);
  context.restore(); // 描画スタイルを復元
}
start();
</script>

 
 ついでに、javaでも作った(というか、はじめにjavaで書いてからjavascriptに翻訳した)。swing。以下、ソースコード。90行くらい。
 

import java.awt.Container;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;

public class Rotate extends JFrame {
  public Rotate() {
    setTitle("くるくる回るおもちゃ");
    MainPanel panel = new MainPanel();
    Container contentPane = getContentPane();
    contentPane.add(panel);
    pack();
  }
  
  public static void main(String[] args) {
    Rotate frame = new Rotate();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }
}

class MainPanel extends JPanel implements Runnable, MouseMotionListener {
  public static final int SCREEN_SIZE = 282; // パネルサイズ
  private Motor motor; // モーター
  private Thread thread; // スレッド
  
  public MainPanel() {
    setPreferredSize(new Dimension(SCREEN_SIZE, SCREEN_SIZE));
    setFocusable(true);
    addMouseMotionListener(this);
    motor = new Motor();
    thread = new Thread(this);
    thread.start();
  }
  
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    motor.draw(g); // モーターを描画
  }
  
  public void run() {
    while(true) { // メインループ
      motor.rotate(); // モーターを回転させる
      repaint();
      try {
        Thread.sleep(10);
      } catch(InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
  
  public void mouseMoved(MouseEvent e) {
    motor.x = e.getX(); // 磁石を移動する
    motor.y = e.getY();
    motor.distance = Math.sqrt((SCREEN_SIZE / 2 - motor.x) * (SCREEN_SIZE / 2 - motor.x) + (SCREEN_SIZE / 2 - motor.y) * (SCREEN_SIZE / 2 - motor.y));
  }
  
  public void mouseDragged(MouseEvent e) {}
}

class Motor {
  public int x;
  public int y;
  public double angle = 0; // 角度
  public double distance; // モーターの中心と棒のあいだの距離
  public double speed; // 速度
  public double acceleration; // 加速度
  public double resistance = 0.05; // 空気抵抗
  
  public void rotate() { // 回転速度を決めて、角度に加算する
    if(angle > 90) angle -= 90d; // 角度は90進数
    acceleration = 0.1 - (distance / 1000d); // 0.1は最高速度。モーターの中心から磁石が離れると減算される
    if(acceleration > 0) speed += acceleration; // 加速度が0以上なら加速
    speed -= resistance; // モーターは常に空気抵抗を受ける
    if(speed >= 0) angle += speed; else speed = 0; // 速度が0以上なら加速。マイナスなら0
  }

  public void draw(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    AffineTransform af = new AffineTransform();
    af.setToRotation(angle * Math.PI/180, MainPanel.SCREEN_SIZE / 2, MainPanel.SCREEN_SIZE / 2); // モーターを回転
    g2.setTransform(af);
    g.fillRect(MainPanel.SCREEN_SIZE / 2 - 100, MainPanel.SCREEN_SIZE / 2 - 100, 200, 200); // モーターを描画
  }
}