デモ: http://cnwander.com/demo/billiards/
元のアドレス: http://cnwander.com/blog/?p=11
JSミニゲームシリーズ:
【JSミニゲーム】スネーク+詳細コメント
最初にコードを貼り付けます。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd ">
<html xmlns=" http://www.w3.org/1999/xhtml ">
<頭>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>CNwander のビリヤード</title>
<style type="text/css">
* {マージン:0; パディング:0}
本文 {背景:黒; フォントサイズ:12px}
h1 {フォントサイズ:12px; フォントの太さ:標準;
h1 .sub {垂直整列:スーパー; フォントサイズ:9px;
.info {位置: 絶対右: 0; 色: グレー}
#table {位置:相対; 幅:20px; 高さ:544px ; _background:none; _filter:progid='true', sizingMethod='スケール', src= ); _background:none; _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src= ); _background:none; .AlphaImageLoader(enabled='true', sizingMethod='scale', src= ) no-repeat}
#force {位置: 絶対; 左: 18px; 幅: 20px; フォントサイズ: 1px}
#スコアボード {位置:絶対値; 左:346ピクセル; フィルター:アルファ(不透明度=0); }
#tips {パディング:15px 0 0 20px; フォントサイズ:12px;
</スタイル>
<script type="text/javascript">
// 一般
関数 $(str) {
document.getElementById(str) を返します。
}
関数 $tag(str,target) {
ターゲット = ターゲット ドキュメント;
target.getElementsByTagName(str) を返します。
}
関数 addEventHandler(obj,eType,fuc){
if(obj.addEventListener){
obj.addEventListener(eType,fuc,false);
}else if(obj.attachEvent){
obj.attachEvent("on" + eType,fuc);
}それ以外{
obj["on" + eType] = fuc;
}
}
関数removeEventHandler(obj,eType,fuc){
if(obj.removeEventListener){
obj.removeEventListener(eType,fuc,false);
}else if(obj.attachEvent){
obj.detachEvent("on" + eType,fuc);
}
}
関数 randowNum(開始,終了) {
return Math.floor(Math.random()*(end - start)) + start;
}
Array.prototype.remove=function(dx) {
if(isNaN(dx)||dx>this.length){return false;}
for(var i=0,n=0;i<this.length;i++)
{
if(この[i]!=この[dx])
{
これ[n++]=これ[i]
}
}
this.length-=1
}
//定数
var TOTALR = 15, //ボールの半径(影を含む)
R = 12, //ボールの実際の半径
ポーカー = 20、
W = 736, //ケースの幅
H = 480, //ケースの高さ
厚さ = 32, //エッジの厚さ
RATE = 100, //リフレッシュ頻度
F = 0.01, //摩擦力
LOSS = 0.2, // 衝突速度の損失
TIPS = ["ヒント 1: 基準ボール、ターゲット ボール、ターゲット バッグ、3 点と 1 つのライン、これがゴールを決める最も基本的な方法です","ヒント 2: 右下の青いバーは打撃力を表します。小さな力手球の位置を制御するのが簡単です。」、「ヒント 3: 右下の白いボールの青い点が打点を制御します。これは、ハイバー、ローバー、プラグを制御します。マスターとマスターの違いはここにあります。 ","ヒント 4: 卓球では、ターゲット ボールは実際にプレーされるのではなく、手球です。"];
var テーブル、//case
cueBall, //キューボール
guideBall, //基準球
dotWrap, //基準線
速度 = 12、
ロールアップ = 0、
rollRight = 0、
タイマー、
フォースタイマー、
ボール = []、
移動ボール = []、
ポーク = [[0,0],[W/2,-5],[W,0],[0,H],[W/2,H+5],[W,H]],
hasShot = false;
ショット = 0 //コンボショットの数;
window.onload = function() {
initTable();
initShootPos();
showTips();
startGame();
}
関数 startGame() {
initBall();
addEventHandler(テーブル,"マウス移動",dragCueBall);
addEventHandler(テーブル,"マウスアップ",setCueBall);
}
関数 initTable() {
テーブル = $("テーブル");
var dotWrapDiv = document.createElement("div"),
guideBallDiv = document.createElement("div");
dotWrapDiv.id = "ドットラップ";
guideBallDiv.className = "ガイド ボール";
setStyle(guideBallDiv,"表示","なし");
dotWrap = table.appendChild(dotWrapDiv);
guideBall = table.appendChild(guideBallDiv);
}
関数 initBall() {
//手球を追加
cueBall = new Ball("cue",170,H/2);
ボール.プッシュ(キューボール);
//ターゲットボールを追加
for(var i = 0; i < 5; i++) {
for(var j = 0; j <= i; j++) {
var ball = new Ball("ターゲット",520 + i*2*R, H/2 - R*i + j*2*R);
ボール.プッシュ(ボール);
}
}
}
関数 initShootPos() {
var ラップ = $("shootPos"),
ハンドラー = $("ドット"),
矢印R = 18;
addEventHandler(wrap,"mousedown",selectDot);
関数 selectDot(e) {
e = e || イベント;
var pos = getElemPos(wrap),
x = e.clientX - pos[0] - handler.offsetWidth/2、
y = e.clientY - pos[1] - handler.offsetHeight/2;
if(Math.sqrt((x-22)*(x-22) + (y-22)*(y-22)) > arrowR) {
var angle = Math.atan2(x-22,y-22);
x = arrowR*Math.sin(角度) + 22;
y = arrowR*Math.cos(角度) + 22;
}
setPos(ハンドラー,x,y);
}
}
関数 getElemPos(ターゲット,参照) {
参照 = ドキュメント ||
var left = 0、top = 0;
getPos(ターゲット)を返します;
関数 getPos(ターゲット) {
if(ターゲット != 参照) {
左 += ターゲット.オフセット左;
トップ += ターゲット.オフセットトップ;
getPos(target.parentNode) を返します。
} それ以外 {
[左,上]を返します;
}
}
}
// ボールクラス
関数 Ball(タイプ,x,y) {
var div = document.createElement("div");
div.className = タイプ + "ボール";
this.elem = table.appendChild(div);
this.type = タイプ;
this.x = x; //位置
this.y = y;
this.angle = 0;
this.v = 0; //速度(方向を除く)
setBallPos(this.elem,x,y);
これを返します。
}
関数 setCueBall() {
RemoveEventHandler(テーブル,"マウス移動",dragCueBall);
RemoveEventHandler(テーブル,"マウスアップ",setCueBall);
startShot();
}
関数 startShot() {
show(cueBall.elem);
addEventHandler(table,"mousemove",showGuide);
addEventHandler(テーブル,"マウスダウン",updateForce);
addEventHandler(テーブル,"マウスアップ",shotCueBall);
}
関数ドラッグキューボール(e) {
var toX,toY;
e = e || イベント;
toX = e.clientX - table.offsetLeft - THICKNESS、
toY = e.clientY - table.offsetTop - THICKNESS;
toX = toX >= R ? toX : R;
toX = toX <= 170 ? toX : 170;
toY = toY >= R ? toY : R;
toY = toY <= H - R ? toY : H - R;
setBallPos(cueBall,toX,toY);
}
関数shotCueBall() {
RemoveEventHandler(table,"mousemove",showGuide);
RemoveEventHandler(table,"mousedown",updateForce);
RemoveEventHandler(テーブル,"マウスアップ",shotCueBall);
window.clearInterval(forceTimer);
速度 = $("force").offsetWidth * 0.15;
var dotDisX = $("dot").offsetLeft-22,
dotDisY = $("dot").offsetTop-22,
dotDis = Math.sqrt(dotDisX*dotDisX + dotDisY*dotDisY),
dotAngle = Math.atan2(dotDisX,dotDisY);
rollRight = Math.round(dotDis*Math.sin(dotAngle))/5;
rollUp = -Math.round(dotDis*Math.cos(dotAngle))/5;
var formPos = getBallPos(cueBall.elem),
toPos = getBallPos(guideBall),
angle = Math.atan2(toPos[0] - formPos[0],toPos[1] - formPos[1]);
非表示(dotWrap);
非表示(ガイドボール);
cueBall.v = 速度;
cueBall.angle = 角度;
ムービングボール.push(cueBall);
timer = window.setInterval(roll,1000 / RATE);
}
関数 showGuide(e) {
var fromX、fromY、toX、toY;
e = e || イベント;
toX = e.clientX - table.offsetLeft - THICKNESS、
toY = e.clientY - table.offsetTop - THICKNESS;
setBallPos(guideBall,toX,toY);
show(dotWrap);
show(ガイドボール);
描画ライン();
//基準線
関数drawLine() {
var dotNum = 16、
pos = getBallPos(cueBall.elem);
dotWrap.innerHTML = "";
fromX = pos[0];
fromY = pos[1];
varpartX = (toX - fromX) / dotNum,
パートY = (toY - fromY) / dotNum;
for(var i = 1; i < dotNum; i++) {
var x = fromX +partX * i、
y = fromY +partY * i;
drawDot(dotWrap, x, y);
}
}
}
関数 roll() {
if(movingBalls.length <= 0) {
if(!hasShot) ショット = 0;
else ショット ++ // 蓄積されたコンボ
hasShot = false;
setStyle($("force"),"width",80+"px");
setPos($("ドット"),22,22);
window.clearInterval(タイマー);
if(shots > 1) showScore(shots); //コンボ数を表示します。
startShot();
}
for(var i = 0; i < moveBalls.length; i++) {
var ball = 移動ボール[i]、
sin = Math.sin(ball.angle),
cos = Math.cos(ball.angle);
ball.v -= F;
//静止しているボールを取り除く
if(Math.round(ball.v) == 0) {
ball.v = 0;
moveBalls.remove(i);
続く;
}
var vx = ball.v * sin、
vy = ball.v * cos;
ボール.x += vx;
ball.y += vy;
//カバンに入れます
if(isPocket(ball.x,ball.y)) {
隠す(ball.elem);
if(ball.type == "キュー") {
if(!hasShot) ショット = 0;
hasShot = false;
window.setTimeout(function(){
ball.v = 0;
setBallPos(ボール,170,250);
},500);
}それ以外 {
//袋に入ったボールを取り出す
hasShot = true;
ball.v = 0;
for(var k = 0, l =0; k < ball.length; k++) {
if(ボール[k] != ボール) {
ボール[l++] = ボール[k];
}
}
ボールの長さ -= 1;
}
戻る;
}
//エッジ衝突
if(ball.x < R || ball.x > W - R) {
ボール角度 *= -1;
ball.angle %= Math.PI;
ball.v = ball.v * (1 - 損失);
vx = ball.v*Math.sin(ball.angle);
vy = ball.v*Math.cos(ball.angle);
if(ball.x < R) ball.x = R;
if(ball.x > W - R) ball.x = W - R;
//手球の詰め物
if(ball.type == "キュー") {
if(ball.angle > 0) vy -= rollRight;
それ以外の場合は vy += rollRight;
vx += ロールアップ;
ロールアップ *= 0.2;
ロール右 *= 0.2;
ball.v = Math.sqrt(vx*vx + vy*vy);
ball.angle = Math.atan2(vx,vy);
}
}
if(ball.y < R || ball.y > H - R) {
ボール.角度 = ボール.角度 > 0 ? Math.PI - ボール.角度 : - Math.PI - ボール.角度 ;
ball.angle %= Math.PI;
ball.v = ball.v * (1 - 損失);
vx = ball.v*Math.sin(ball.angle);
vy = ball.v*Math.cos(ball.angle);
if(ball.y < R) ball.y = R;
if(ボール.y > H - R) ボール.y = H - R;
//手球の詰め物
if(ball.type == "キュー") {
if(Math.abs(ball.angle) < Math.PI/2) vx += rollRight;
それ以外の場合、vx -= ロール右;
vy += ロールアップ;
ロールアップ *= 0.2;
ロール右 *= 0.2;
ball.v = Math.sqrt(vx*vx + vy*vy);
ball.angle = Math.atan2(vx,vy);
}
}
//ボールの衝突
for(var j = 0; j < ball.length; j++) {
var obj = ボール[j];
if(obj == ball) 続行;
var disX = obj.x - ball.x、
disY = obj.y - ball.y、
ギャップ = 2 * R;
if(disX <= ギャップ && disY <= ギャップ) {
var dis = Math.sqrt(Math.pow(disX,2)+Math.pow(disY,2));
if(dis <= ギャップ) {
//静止している場合は配列に追加しますmovingBalls
if(Math.round(obj.v) == 0)
ムービングボール.push(obj);
//衝突計算のために座標を X 軸に回転します
// 角度、サイン値、コサイン値を計算します - 正確な値
//var c = (obj.x*ball.y - obj.y*ball.x)/(2*R),
// d = Math.sqrt(ball.x*ball.x + ball.y*ball.y),
// 角度 = Math.asin(ball.y/d) - Math.asin(c/d) - ball.angle%(Math.PI/2),
//角度 = Math.asin(oy / (2 * R)),
// 2 つのボールの接線状態を復元 - 近似値
ball.x -= (ギャップ - ディス)*sin;
ball.y -= (ギャップ - ディス)*cos;
disX = obj.x - ball.x;
disY = obj.y - ball.y;
// 角度、サイン値、コサイン値を計算します。
var angle = Math.atan2(disY, disX),
hitin = Math.sin(角度)、
hitcos = Math.cos(角度)、
objVx = obj.v * Math.sin(obj.angle),
objVy = obj.v * Math.cos(obj.angle);
//trace(角度*180/Math.PI);
// 座標を回転します
var x1 = 0、
y1 = 0、
x2 = disX * hitcos + disY * hitin、
y2 = disY * hitcos - disX * hitin、
vx1 = vx * hitcos + vy * hitin、
vy1 = vy * hitcos - vx * hitin、
vx2 = objVx * hitcos + objVy * hitin、
vy2 = objVy * hitcos - objVx * hitin;
// 衝突後の速度と位置
var plusVx = vx1 - vx2;
vx1 = vx2;
vx2 = プラス Vx + vx1;
//手球の詰め物
if(ball.type == "キュー") {
vx1 += ロールアップ;
ロールアップ *= 0.2;
}
x1 += vx1;
x2 += vx2;
// 位置を後方に回転します
var x1Final = x1 * hitcos - y1 * hitin、
y1Final = y1 * hitcos + x1 * hitin、
x2Final = x2 * hitcos - y2 * hitin、
y2Final = y2 * hitcos + x2 * hitin;
obj.x = ball.x + x2Final;
obj.y = ball.y + y2Final;
ball.x = ball.x + x1Final;
ball.y = ball.y + y1Final;
// 速度を元に戻します
vx = vx1 * hitcos - vy1 * hitin;
vy = vy1 * hitcos + vx1 * hitin;
objVx = vx2 * hitcos - vy2 * hitin;
objVy = vy2 * hitcos + vx2 * hitin;
//最終速度
ball.v = Math.sqrt(vx*vx + vy*vy) * (1 - 0);
obj.v = Math.sqrt(objVx*objVx + objVy*objVy) * (1 - 0);
// 角度を計算する
ball.angle = Math.atan2(vx , vy);
obj.angle = Math.atan2(objVx , objVy);
//壊す;
}
}
}
setBallPos(ボール,ボール.x,ボール.y);
}
}
関数 isPocket(x,y) {
if(y < POKER) return check(0,2);
else if (y > H - POKER) return check(3,5);
それ以外の場合は false を返します。
関数チェック(m,n) {
for(var i=m; i<=n; i++) {
if(x >= pokes[i][0] - POKER && x <= pokes[i][0] + POKER) {
var dis = Math.sqrt(Math.pow(x - pokes[i][0],2) + Math.pow(y - pokes[i][1],2));
if(dis <= POKER) は true を返します。
それ以外の場合は false を返します。
}
}
}
}
関数 getBallPos(obj) {
var pos = [];
pos.push(obj.offsetLeft - THICKNESS + TOTALR);
pos.push(obj.offsetTop - 厚さ + 合計);
返却位置;
}
関数 setPos(obj,x,y) {
obj.style.left = x + "px";
obj.style.top = y + "px";
}
関数 setBallPos(ボール,x,y) {
if(ball.constructor == ボール) {
ボール.x = x;
ボール.y = y;
ボール = ball.elem;
}
setPos(ボール,x + THICKNESS - TOTALR,y + THICKNESS - TOTALR);
}
関数drawDot(wrap,x,y) {
var elem = document.createElement("div");
setStyle(elem,{
位置: "絶対"、
幅: "1px",
高さ: "1px",
フォントサイズ: "1px",
背景:「白」
});
setPos(elem,x,y);
ラップ.appendChild(elem);
}
関数 updateForce() {
var obj = $("力"),
レン = 80、
アップ = true;
ForceTimer = window.setInterval(update,10);
関数 update() {
if(up) setStyle(obj,"width",len+++"px");
それ以外の場合は setStyle(obj,"width",len--+"px");
if(len > 136) アップ = false;
if(len <= 0) アップ = true;
}
}
関数 setStyle() {
if(arguments.length == 2 && 引数の種類[1] == "オブジェクト") {
for(引数[1]のvarキー) {
引数[0].スタイル[キー] = 引数[1][キー];
}
else if (arguments.length > 2) {
引数[0].スタイル[引数[1]] = 引数[2];
}
}
関数非表示(obj) {
setStyle(obj,"表示","なし");
}
関数 show(obj) {
setStyle(obj,"表示","ブロック");
}
//情報を出力する
関数トレース(sth,who) {
誰 = 誰 || $("ヒント");
if(document.all) who.innerText = sth;
それ以外の場合はwho.textContent = sth;
誰を返します。
}
関数 showScore(n) {
var ラップ = $("スコアボード");
トレース(n+「コネクティング ロッド」,ラップ);
フェードイン(ラップ);
}
関数 fadeIn(obj){
変数 fromY = 230、
posStep = [8,14,19,23,26,28,29,29,30,30,30],
opaStep = [0,0.05,0.1,0.15,0.2,0.25,0.3,0.4,0.5,0.6,0.8],
fromOpa = 0、
t = 0、
ステップ = posStep.length、
inTimer = window.setInterval(showIn,20),
アウトタイマー;
関数 showIn() {
setOpacity(obj,opaStep[t]);
obj.style.top = fromY + posStep[t] + "px";
t++;
if(t>=ステップ) {
window.clearInterval(inTimer);
outTimer = window.setInterval(fadeOut,50);
}
}
関数フェードアウト() {
と――;
setOpacity(obj,opaStep[t]);
obj.style.top = fromY + posStep[t] + "px";
if(t <= 0) {
window.clearInterval(outTimer);
非表示(obj);
}
}
}
関数 setOpacity(obj,n) {
obj.style.cssText = "filter:alpha(opacity="+ n*100 +"); -moz-opacity:"+ n +"; opacity:"+ n;
}
関数 showTips() {
変数 i = 0;
ヒント();
window.setInterval(tip,3000);
関数ヒント() {
トレース(TIPS[i++]);
if(i >= TIPS.length) i = 0;
}
}
</script>
</head>
<本文>
<div class="info">ディスカッション: <a href=" http://bbs.blueidea.com/thread-2951566-1-1.html"> Blueidea</a >   ; //cnwander.com/blog/?p=11">ワンダーのスペース</a></div>
<h1>中国人は立ち上がれ! <span class="sub">60 周年</span></h1>
<div id="テーブル">
<div id="スコアボード"></div>
</div>
<div class="ボット">
<div id="ヒント"></div>
<div クラス = "ctrl">
<div id="force"></div>
<div id="シュート位置">
<div id="dot"></div>
</div>
</div>
</div>
</body>
</html>
恥ずかしながら卓球と名付けられていますが、実際は本物の卓球とは程遠く、改善の余地はまだまだたくさんあります。
解決すべき具体的な問題:
きっと他にもたくさんの問題があり、休暇中に気が散ってしまい、後で続きができなくなるのではないかと心配しています。少し急いでいますので、後でゆっくりと問題を解決します。このトピックに興味がある学生のために最初に投稿します。
大学の数学は基本的に形式的なもので、高校の物理と数学についてはほとんど忘れていませんでしたが、実際に取り組み始めて初めて、この分野での経験が豊富であることを実感しました。エリアがアドバイスをくれるでしょう。