العرض التوضيحي: 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>
<نمط النوع = "نص/CSS">
* {الهامش:0؛
الجسم {الخلفية: أسود - محاذاة النص: حجم الخط: 12 بكسل}
h1 {حجم الخط: 12 بكسل؛ اللون: رمادي؛ ارتفاع الخط: عادي؛
h1 .sub {vertical-align:super;
.معلومات {الموضع:يمين مطلق:0؛
#table {position:relative width:800px ; هامش: 20px ارتفاع تلقائي:544px; ; .AlphaImageLoader(enabled='true', sizingMethod='scale', src=" ) بدون تكرار}
#force {position:absolute left:0 ;
#scoreBoard {position:absolute; z-index:3; top:230px left:346px; }
#نصائح {padding:15px 0 0 20px؛ محاذاة النص:left؛
</نمط>
<نوع البرنامج النصي = "نص/جافا سكريبت">
// شائع
الدالة $(شارع) {
إرجاع document.getElementById(str);
}
الدالة $tag(str,target) {
الهدف = الهدف ||.
إرجاع target.getElementsByTagName(str);
}
وظيفة addEventHandler(obj,eType,fuc){
إذا (obj.addEventListener){
obj.addEventListener(eType,fuc,false);
}else if(obj.attachEvent){
obj.attachEvent("on" + eType,fuc);
}آخر{
obj["on" + eType] = fuc;
}
}
وظيفة إزالةEventHandler(obj,eType,fuc){
إذا (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) {
إذا (isNaN(dx)||dx>this.length){return false;}
ل(var i=0,n=0;i<this.length;i++)
{
إذا (هذا [i]! = هذا [dx])
{
هذا [ن ++] = هذا [أنا]
}
}
this.length-=1
}
//const
var TOTALR = 15, // نصف قطر الكرة (بما في ذلك الظل)
R = 12, // نصف القطر الحقيقي للكرة
بوكر = 20،
ث = 736، // عرض الحالة
ح = 480، //ارتفاع الحالة
السُمك = 32، // سُمك الحافة
المعدل = 100، // تردد التحديث
F = 0.01، // قوة الاحتكاك
الخسارة = 0.2، // فقدان سرعة الاصطدام
TIPS = ["Tip1: الكرة المرجعية، كرة الهدف، حقيبة الهدف، ثلاث نقاط وخط واحد، هذه هي الطريقة الأساسية لتسجيل الأهداف"،"Tip2: يمثل الشريط الأزرق الموجود في الزاوية اليمنى السفلية قوة الضربة. القوة الصغيرة" من الأسهل التحكم في موضع الكرة الرئيسية"، "نصيحة 3: النقطة الزرقاء الموجودة على الكرة البيضاء في الزاوية اليمنى السفلية تتحكم في نقطة الضرب، فهي تتحكم في الشريط العالي والشريط المنخفض والقابس غالبًا ما يكون الفرق بين الماجستير والماجستير ""،"Tip4: في تنس الطاولة، لا يتم لعب الكرة المستهدفة فعليًا، بل هي الكرة الرئيسية"];
جدول فار، //case
كرة جديلة، // كرة جديلة
GuideBall، // الكرة المرجعية
dotWrap، // السطر المرجعي
السرعة = 12،
التراكمي = 0،
لفة لليمين = 0،
مؤقت,
فورستايمر,
الكرات = []،
الكرات المتحركة = []،
الوخزات = [[0,0]،[W/2،-5]،[W،0]،[0،H]،[W/2،H+5]،[W،H]]،
hasShot = false;
اللقطات = 0؛ // عدد اللقطات المجمعة
نافذة.onload = وظيفة () {
initTable();
initShootPos();
showTips();
startGame();
}
وظيفة بداية اللعبة () {
initBall();
addEventHandler(table,"mousemove",dragCueBall);
addEventHandler(table,"mouseup",setCueBall);
}
الدالة initTable() {
الجدول = $("الجدول");
فار dotWrapDiv = document.createElement("div"),
GuideBallDiv = document.createElement("div");
dotWrapDiv.id = "dotWrap";
GuideBallDiv.className = "كرة التوجيه";
setStyle(guideBallDiv،"display"،"none")؛
dotWrap = table.appendChild(dotWrapDiv);
GuideBall = table.appendChild(guideBallDiv);
}
وظيفة initBall() {
// أضف كرة جديلة
cueBall = new Ball("cue",170,H/2);
balls.push(cueBall);
// أضف الكرة المستهدفة
ل(فار i = 0; أنا < 5; i++) {
for(var j = 0; j <= i; j++) {
var ball = new Ball("target",520 + i*2*R, H/2 - R*i + j*2*R);
balls.push(ball);
}
}
}
الدالة initShootPos() {
فار التفاف = $("shootPos")،
المعالج = $("نقطة")،
السهمR = 18؛
addEventHandler(wrap,"mousedown",selectDot);
وظيفة تحديد دوت (ه) {
e = e ||.
فار pos = getElemPos(التفاف)،
x = e.clientX - pos[0] - Handler.offsetWidth/2,
y = e.clientY - pos[1] - Handler.offsetHeight/2;
إذا(Math.sqrt((x-22)*(x-22) + (y-22)*(y-22)) > ArrowR) {
زاوية فار = Math.atan2(x-22,y-22);
x = سهمR*Math.sin(angle) + 22;
y = ArrowR*Math.cos(angle) + 22;
}
setPos(handler,x,y);
}
}
دالة getElemPos(target,reference) {
مرجع = مرجع ||.
فار يسار = 0,أعلى = 0;
إرجاع getPos(target);
وظيفة getPos (الهدف) {
إذا (الهدف!= مرجع) {
left += target.offsetLeft;
top += target.offsetTop;
إرجاع getPos(target.parentNode);
} آخر {
العودة [يسار، أعلى]؛
}
}
}
// فئة الكرة
وظيفة الكرة (نوع، س، ص) {
var div = document.createElement("div");
div.className = type + "ball";
this.elem = table.appendChild(div);
this.type = type;
this.x = x;
this.y = y;
this.angle = 0;
this.v = 0; // السرعة (باستثناء الاتجاه)
setBallPos(this.elem,x,y);
رد هذا؛
}
وظيفة مجموعةCueBall () {
RemoveEventHandler(table,"mousemove",dragCueBall);
RemoveEventHandler(table,"mouseup",setCueBall);
startShot();
}
وظيفة ستارت شوت () {
show(cueBall.elem);
addEventHandler(table,"mousemove",showGuide);
addEventHandler(table,"mousedown",updateForce);
addEventHandler(table,"mouseup",shotCueBall);
}
وظيفة DragCueBall(e) {
فار toX,toY;
e = e ||.
toX = e.clientX - table.offsetLeft - السُمك،
toY = e.clientY - table.offsetTop - THICKNESS؛
toX = toX >= R ? toX : R;
توكس = توكس <= 170 ? توكس : 170;
toY = toY >= R ?
لعبة = لعبة <= H - R ?
setBallPos(cueBall,toX,toY);
}
وظيفة شوتكيوبول () {
RemoveEventHandler(table,"mousemove",showGuide);
RemoveEventHandler(table,"mousedown",updateForce);
RemoveEventHandler(table,"mouseup",shotCueBall);
window.clearInterval(forceTimer);
السرعة = $("force").offsetWidth * 0.15;
فار 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;
فار فورمبوس = getBallPos(cueBall.elem),
toPos = getBallPos(guideBall)،
angle = Math.atan2(toPos[0] - formPos[0],toPos[1] - formPos[1]);
إخفاء(dotWrap);
إخفاء(guideBall);
cueBall.v = السرعة؛
cueBall.angle = angle;
moveBalls.push(cueBall);
timer = window.setInterval(roll,1000 / RATE);
}
دليل عرض الوظيفة (هـ) {
فار fromX,fromY,toX,toY;
e = e ||.
toX = e.clientX - table.offsetLeft - السُمك،
toY = e.clientY - table.offsetTop - THICKNESS؛
setBallPos(guideBall,toX,toY);
show(dotWrap);
show(guideBall);
drawLine();
// السطر المرجعي
وظيفة رسم الخط () {
فار دوتنوم = 16،
pos = getBallPos(cueBall.elem);
dotWrap.innerHTML = "";
fromX = pos[0];
fromY = pos[1];
فار بارتكس = (toX - fromX) / dotNum،
partyY = (toY - fromY) / dotNum؛
for(var i = 1; i < dotNum; i++) {
فار x = fromX + PartX * i,
y = fromY + partyY * i;
drawDot(dotWrap, x, y);
}
}
}
لفة الوظيفة () {
إذا (movingBalls.length <= 0) {
if(!hasShot) shots = 0;
لقطات أخرى ++؛ // المجموعات المتراكمة
hasShot = false;
setStyle($("force"),"width",80+"px");
setPos($("dot"),22,22);
window.clearInterval(timer);
if(shots > 1) showScore(shots); // أظهر عدد المجموعات
startShot();
}
for(var i = 0; i < movingBalls.length; i++) {
فار بول = كرات متحركة[i]،
الخطيئة = Math.sin(ball.angle)،
cos = Math.cos(ball.angle);
ball.v -= F;
// قم بإزالة الكرة الثابتة
إذا(Math.round(ball.v) == 0) {
ball.v = 0;
moveBalls.remove(i);
يكمل؛
}
فار vx = ball.v * الخطيئة،
vy = ball.v * cos;
ball.x += vx;
ball.y += vy;
// ضعه في الحقيبة
إذا (isPocket(ball.x,ball.y)) {
إخفاء(ball.elem);
إذا (ball.type == "جديلة") {
if(!hasShot) shots = 0;
hasShot = false;
window.setTimeout(function(){
ball.v = 0;
setBallPos(ball,170,250);
},500);
}آخر {
// قم بإزالة الكرات المعبأة
hasShot = true;
ball.v = 0;
for(var k = 0, l =0; k < balls.length; k++) {
إذا (كرات [ك] ! = الكرة) {
الكرات[l++] = الكرات[k];
}
}
طول الكرات -= 1;
}
يعود؛
}
// تصادم الحافة
إذا (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);
إذا (ball.x < R) ball.x = R؛
if(ball.x > W - R) ball.x = W - R;
// حشو الكرة
إذا (ball.type == "جديلة") {
if(ball.angle > 0) vy -= rollRight;
else vy += rollRight;
vx += rollUp;
رول اب *= 0.2;
rollRight *= 0.2;
ball.v = Math.sqrt(vx*vx + vy*vy);
ball.angle = Math.atan2(vx,vy);
}
}
إذا (ball.y < R || ball.y > H - R) {
ball.angle = ball.angle > 0 ? Math.PI - ball.angle : - Math.PI - ball.angle ;
ball.angle %= Math.PI;
ball.v = ball.v * (1 - الخسارة)؛
vx = ball.v*Math.sin(ball.angle);
vy = ball.v*Math.cos(ball.angle);
إذا (ball.y < R) ball.y = R؛
if(ball.y > H - R) ball.y = H - R;
// حشو الكرة
إذا (ball.type == "جديلة") {
if(Math.abs(ball.angle) < Math.PI/2) vx += rollRight;
else vx -= rollRight;
vy += rollUp;
رول اب *= 0.2;
rollRight *= 0.2;
ball.v = Math.sqrt(vx*vx + vy*vy);
ball.angle = Math.atan2(vx,vy);
}
}
// اصطدام الكرة
for(var j = 0; j < balls.length; j++) {
var obj = balls[j];
if(obj == ball) continue;
فار ديسك = obj.x - ball.x،
ديسي = obj.y - ball.y،
الفجوة = 2 * ر؛
إذا (ديسكس <= فجوة && ديزي <= فجوة) {
var dis = Math.sqrt(Math.pow(disX,2)+Math.pow(disY,2));
إذا (ديس <= الفجوة) {
// إذا كانت ثابتة، أضفها إلى المصفوفة movingBalls
إذا (Math.round(obj.v) == 0)
moveBalls.push(obj);
// قم بتدوير الإحداثيات إلى المحور السيني لحساب الاصطدام
// حساب قيم الزاوية والجيب وجيب التمام - القيم الدقيقة
//var c = (obj.x*ball.y - obj.y*ball.x)/(2*R)،
// د = 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)))،
// استعادة حالة الظل للكرتين - قيمة تقريبية
ball.x -= (فجوة - ديس)*خطيئة;
ball.y -= (فجوة - ديس)*cos;
DisX = obj.x - ball.x;
disY = obj.y - ball.y;
// حساب قيم الزاوية وجيب التمام وجيب التمام
زاوية فار = Math.atan2(disY, disX),
هيتسين = Math.sin(زاوية)،
Hitcos = Math.cos(زاوية)،
objVx = obj.v * Math.sin(obj.angle)،
objVy = obj.v * Math.cos(obj.angle);
//تتبع(زاوية*180/Math.PI);
// تدوير الإحداثيات
فار x1 = 0,
ص1 = 0،
x2 = disX * hitcos + disY * hitsin،
y2 = disY * hitcos - disX * hitsin،
vx1 = vx * hitcos + vy * hitsin،
vy1 = vy * hitcos - vx * hitsin،
vx2 = objVx * hitcos + objVy * hitsin،
vy2 = objVy * hitcos - objVx * hitsin;
// السرعة والموقع بعد الاصطدام
فار plusVx = vx1 - vx2;
vx1 = vx2;
vx2 = plusVx + vx1;
// حشو الكرة
إذا (ball.type == "جديلة") {
vx1 += rollUp;
رول اب *= 0.2;
}
x1 += vx1;
x2 += vx2;
// قم بتدوير الموضع للخلف
فار x1Final = x1 * هيتكوس - y1 * هيتسين،
y1Final = y1 * هيتكوس + x1 * هيتسين،
x2Final = x2 * hitcos - y2 * hitsin،
y2Final = y2 * hitcos + x2 * hitsin;
obj.x = ball.x + x2Final;
obj.y = ball.y + y2Final;
ball.x = ball.x + x1Final;
ball.y = ball.y + y1Final;
// قم بتدوير السرعة للخلف
vx = vx1 * hitcos - vy1 * hitsin؛
vy = vy1 * hitcos + vx1 * hitsin;
objVx = vx2 * hitcos - vy2 * hitsin;
objVy = vy2 * hitcos + vx2 * hitsin;
// السرعة النهائية
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(ball,ball.x,ball.y);
}
}
الدالة هيPocket(x,y) {
if(y <POKER) return check(0,2);
وإلا إذا (y > H - POKER) قم بإرجاع الاختيار(3,5);
وإلا يعود كاذبا؛
فحص الوظيفة (م، ن) {
for(var i=m;i<=n;i++) {
إذا (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) return true;
وإلا يعود كاذبا؛
}
}
}
}
وظيفة getBallPos(obj) {
فار بوس = []؛
pos.push(obj.offsetLeft - THICKNESS + TOTALR);
pos.push(obj.offsetTop - THICKNESS + TOTALR);
عودة نقاط البيع.
}
وظيفة سيتبوس (obj،x،y) {
obj.style.left = x + "px";
obj.style.top = y + "px";
}
دالة setBallPos(ball,x,y) {
إذا (ball.constructor == الكرة) {
ball.x = x;
ball.y = y;
ball = ball.elem;
}
setPos(ball,x + THICKNESS - TOTALR,y + THICKNESS - TOTALR);
}
دالة drawDot(wrap,x,y) {
var elem = document.createElement("div");
سيت ستايل (عنصر، {
الموقف: "المطلق"،
العرض: "1 بكسل"،
الارتفاع: "1 بكسل"،
حجم الخط: "1px"،
الخلفية: "أبيض"
});
setPos(elem,x,y);
Wrap.appendChild(elem);
}
وظيفة التحديثفورس () {
فار أوبج = $("القوة")،
لين = 80،
يصل = صحيح؛
forceTimer = window.setInterval(update,10);
تحديث الوظيفة () {
if(up) setStyle(obj,"width",len+++"px");
else setStyle(obj,"width",len--+"px");
if(len > 136) up = false;
if(len <= 0) up = true;
}
}
وظيفة سيت ستايل () {
إذا (arguments.length == 2 && نوع الوسائط[1] == "object") {
ل(مفتاح فار في الحجج[1]) {
وسيطات[0].style[مفتاح] = وسيطات[1][مفتاح];
}
} وإلا إذا (arguments.length > 2) {
الوسيطات[0].style[arguments[1]] = الوسيطات[2];
}
}
إخفاء الوظيفة (الكائن) {
setStyle(obj،"display"،"none")؛
}
عرض الوظيفة (الكائن) {
setStyle(obj،"display"،"block")؛
}
// معلومات الإخراج
تتبع الدالة (sth، who) {
من = من ||.$("نصائح");
if(document.all) who.innerText = sth;
else who.textContent = sth;
عودة من؛
}
دالة showScore(n) {
var Wrap = $("scoreBoard");
تتبع (n+"قضيب التوصيل"،التفاف)؛
FadeIn(wrap);
}
وظيفة FadeIn(obj){
فار من Y = 230،
خطوة العمل = [8,14,19,23,26,28,29,29,30,30,30],
أوباستيب = [0,0.05,0.1,0.15,0.2,0.25,0.3,0.4,0.5,0.6,0.8],
من أوبا = 0،
ر = 0،
الخطوة = posStep. length،
inTimer = window.setInterval(showIn,20),
outTimer;
وظيفة شوين () {
setOpacity(obj,opaStep[t]);
obj.style.top = fromY + posStep[t] + "px";
ر++;
إذا (ر> = الخطوة) {
window.clearInterval(inTimer);
outTimer = window.setInterval(fadeOut,50);
}
}
وظيفة تتلاشى () {
ر--؛
setOpacity(obj,opaStep[t]);
obj.style.top = fromY + posStep[t] + "px";
إذا (ر <= 0) {
window.clearInterval(outTimer);
إخفاء(obj);
}
}
}
وظيفة setOpacity(obj,n) {
obj.style.cssText = "filter:alpha(opacity="+ n*100 +"); -moz-opacity:"+ n +"; العتامة:"+ n;
}
وظيفة showTips () {
فار ط = 0؛
نصيحة()؛
window.setInterval(tip,3000);
نصيحة الدالة () {
تتبع(TIPS[i++]);
إذا (i >= TIPS.length) i = 0;
}
}
</script>
</الرأس>
<الجسم>
<div class="info">مناقشة: <a href=" http://bbs.blueidea.com/thread-2951566-1-1.html"> Blueidea</a > <a href=" http: //cnwander.com/blog/?p=11" >مساحة التجوال</a></div>
<h1>الشعب الصيني يقف! <span class="sub">الذكرى الستين</span></h1>
<div معرف = "الجدول">
<div id="scoreBoard"></div>
</div>
<div class="bot">
<div id="tips"></div>
<div class = "ctrl">
<div id="force"></div>
<div معرف = "shootPos">
<div معرف = "dot"></div>
</div>
</div>
</div>
</الجسم>
</html>
على الرغم من تسميتها بلا خجل بتنس الطاولة، إلا أنها في الواقع بعيدة كل البعد عن تنس الطاولة الحقيقي، ولا يزال هناك العديد من المجالات التي تحتاج إلى تحسين.
القضايا المحددة التي يتعين حلها:
سيكون هناك بالتأكيد الكثير من المشاكل الأخرى، وأنا قلق من أنني سأتشتت انتباهي كثيرًا خلال العطلات ولن أتمكن من الاستمرار لاحقًا سأحل المشكلات ببطء لاحقًا وسأقوم بنشرها أولاً للطلاب المهتمين بهذا الموضوع.
إن الرياضيات الجامعية هي في الأساس مجرد إجراء شكلي، وقد نسيت القليل جدًا عن الفيزياء والرياضيات في المدرسة الثانوية، فقط عندما بدأت فعلًا في القيام بالأشياء، أدركت أنني كنت ضعيفًا جدًا في هذا المجال، وأتمنى أن يتمتع الطلاب بخبرة أكبر في هذا المجال المنطقة سوف تعطيني بعض النصائح.