هذا الموضوع سأبني عليه تحديات مستقبلية لنا جميعا -ان شاء الله- ،،،
الكود المستخدم تجدونه من هنا: https://codepen.io/nasr3090/pen/wjrYwe
نسخة من الكود بترتيبي الخاص
<!DOCTYPE html>
<html lang="en">
<!-- ******** Starting head tag ******** -->
<head>
<meta charset="utf-8"/>
<meta name="author" content="Nasr Galal" />
<meta name="copyright" content="Nasr Galal 2018" />
<title>Lesson 2: animation</title>
</head>
<!-- ******** ending head tag ******** -->
<!-- ******** Setting page styles ******** -->
<style>
html {
background: lightgrey;
}
canvas {
border: 1px solid black;
display: block;
margin-left: auto;
margin-right: auto;
}
</style>
<!-- ******** Ending page styles ******** -->
<!-- ******** Starting body tag ******** -->
<body>
<!-- one canvas inbound -->
<canvas id="meow" width="200px" height="200px">
Hi there!
</canvas>
<!-- ending canvas -->
<!-- ******** Setting page scripts ******** -->
<script>
// ********************************* Starting variables section *********************************//
// *************************************************** //
//Naming variables to use for drawings
var canvas, ctx, w, h;
// ************************* Variables for location and movement *************************//
// as for rectangle location and speed | // as for circle location and speed
// |
var recX = 10; /* location in x axis |*/ var cirx = 100; // location in x axis
var recY = 10; /* location in y axis |*/ var ciry = 100; // location in y axis
var speed = 1; /* speed |*/ var rad = 15; // radius
var rectWidth = 30; /*Rectangle width |*/ var spx = 2; // speed in x axis
var rectHeight = 30; /*Rectangle height |*/ var spy = 1; // speed in y axis
// ********************************* Ending variables section *********************************//
// ******** Starting Rules for loading the content ********//
// loading drawings when loading screen
window.onload = function init() {
//Defining The variables
// a. Calling the canvas
canvas = document.querySelector("#meow");
// Saving width & height info.
w = canvas.width;
h = canvas.height;
// b. getting the drawing tool
ctx = canvas.getContext('2d');
//setting Animation details into a main function as a way to organize content
mainLoop(); // This will contain the animation details for all shapes
};
// ******** Ending Rules for loading the content ********//
// ******** Functions Section ********//
//This is the main loop we set to control all the functions...
function mainLoop() {
// 1- clearing canvas
ctx.clearRect(0, 0, w, h);
// drawing process
// a. filled rectangle
filledRect(recX, recY, "red");
// b. filled circle
filledCircle(cirx, ciry, rad, "green");
//animation movements
//a. the rectangle
recAnimation(); // this is to call the function For rectangle animation
//--------------------
// b. for the circle
cirAnimation(); // this is to call the function For circle animation
}
//Rules for drawing the rectangle
function filledRect(x, y, color) {
//Saving the above tempelate (x, y, color) to be able to substitute them in line 61
ctx.save();
// translate coordinate system & draw relative to it
ctx.translate(x, y); // Check line 61 >> I substituted the x,y values with locations
// defining the color so that we can substitute in line 61
ctx.fillStyle = color;
// width & height
ctx.fillRect(0, 0, rectWidth, rectHeight); // x & y are set to 0 and I set width and height to be 30 in each
// restoring context to load all the above parameters
ctx.restore();
}
// Rules for drawing the circle
function filledCircle(x, y, rad, color) {
//Saving the above tempelate (x, y, rad, color) to be able to substitute them in line 63
ctx.save();
// translate coordinate system & draw relatie to it
ctx.translate(x, y); // Check line 63 >> I substituted the x,y values with locations
//identifying the color so that we can substitute in line 61
ctx.fillStyle = color;
// identifying radius
ctx.beginPath();
ctx.arc(0, 0, rad, 0, 2*Math.PI);
ctx.fill();
//restoring
ctx.restore();
}
//Rectangle animation rules
function recAnimation() {
recX += speed; // adding speed to the location in x direction
// Testing collision against left and right walls
if (((recX + rectWidth) > w)) {
speed = -speed; //speed direction changes!
}
requestAnimationFrame(mainLoop); //getting new animation frame for the rectangle
}
//Circle animation rules
function cirAnimation() {
// I made the movement in x and y directions
cirx += spx;
ciry += spy;
//collision with walls
// 1. vertical walls --> right wall
if ((cirx + rad) > canvas.width) {
spx = -spx;
cirx = w - rad; //putting ball at collision point
} else if ((cirx - rad) < 0) {
spx = -spx;
cirx = rad; //putting ball at collision point
}
// 2. horizontal walls --> right one
if ((ciry + rad) > canvas.height) {
spy = -spy;
ciry = h - rad;
} else if ((ciry - rad) < 0) {
spy = -spy;
ciry = rad;
}
}
</script>
<!-- ******** ending page scripts ******** -->
</body>
<!-- ******** ending body tag ******** -->
</html>
شكل النتيجة النهائية:
كما نشاهد في الصورة … المعادلات التي تحكم حركة الكرة والمستطيل هي رياضية بحته:
1- حركة المستطيل في اتجاه س أو x
2- حركة الكرة في المحورين (س، ص) أو (x, y)
الـfunctions أو الدوال المستخدمة:
سنقوم بعمل function رئيسية سمّيتها mainLoop تحتوي على الآتي:
- هذا الكود
ctx.clearRect(0, 0, w, h);
لمسح الـcanvas بمحتوياته
ثم إعادة رسمها من جديد كالآتي: - دالة لرسم المستطيل
filledRect()
- دالة لرسم الدائرة
filledCircle()
- دالة لتحريك المستطيل
recAnimation()
- دالة لتحريك الدائرة
cirAnimation()
الأدوات المستخدمة :
أدوات الرسم: https://www.w3schools.com/tags/ref_canvas.asp
التطبيق
كود الmainLoop function
شكل كود ال mainLoop:
//This is the main loop we set to control all the functions...
function mainLoop() {
// 1- clearing canvas
ctx.clearRect(0, 0, w, h);
// drawing process
// a. filled rectangle
filledRect(recX, recY, "red");
// b. filled circle
filledCircle(cirx, ciry, rad, "green");
//animation movements
//a. the rectangle
recAnimation(); // this is to call the function For rectangle animation
//--------------------
// b. for the circle
cirAnimation(); // this is to call the function For circle animation
}
كما ترون هذه كلها استدعاءات للfunctions لكننا لم نقم ببرمجة الfunctions حتى الآن!
لكن هذه الطريقة في رأيي لتبسيط الكود حتى لا يكون طويل جدا … بحيث يمكن عزل كل function على حدة ويمكن استدعائها داخل functions اخرى كما نشاء، وفي أي وقت…
كود رسم المستطيل
//Rules for drawing the rectangle
function filledRect(x, y, color) {
//Saving the above tempelate (x, y, color) to be able to substitute them in line 61
ctx.save();
// translate coordinate system & draw relative to it
ctx.translate(x, y); // Check line 61 >> I substituted the x,y values with locations
// defining the color so that we can substitute in line 61
ctx.fillStyle = color;
// width & height
ctx.fillRect(0, 0, rectWidth, rectHeight); // x & y are set to 0 and I set width and height to be 30 in each
// restoring context to load all the above parameters
ctx.restore();
}
كما تعلمنا سابقا من ورشة عمل 1 … يمكننا رسم المستطيل مع تعديل بسيط…
نلاحظ أني كتبت عدة متغيرات هنا: function filledRect(x, y, color)
والتي سأستخدمها كإطار عمل ثابت، ثم عرفتها كما يلي:
1- نحفظ هذا الترتيب بواسطة الدالة ctx.save();
ثم نطلب الكود ctx.translate(x, y);
والذي يربط الحرفين x, y بنظام الاحداثيات ونلاحظ أني في الأعلى قمت بالتعويض مباشرة عند استدعاء الfunction داخل الmainLoop filledRect(recX, recY, "red");
وهي المتغيرات التي عرفتها سابقا:
var recX = 10; /* location in x axis
var recY = 10; /* location in y axis
يمكنكم التعرف على المزيد عن ctx.save()
من هنا: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore
يمكن ربط ال color بـأداة التلوين في الcanvas وهي ctx.fillstyle
كما بالشكل:
ctx.fillStyle = color;
يتبقى رسم المستطيل مع اعطاء المقاسات ctx.fillRect(0, 0, rectWidth, rectHeight);
وأخيرا الدالة التي تستعيد كل شئ للوضع الافتراضي ctx.restore()
يمكنكم القراءة عنها من هنا: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore
كود رسم الدائرة
بنفس الطريقة نبتكر function مسؤولة عن رسم الدائرة:
// Rules for drawing the circle
function filledCircle(x, y, rad, color) {
//Saving the above tempelate (x, y, rad, color) to be able to substitute them in line 63
ctx.save();
// translate coordinate system & draw relatie to it
ctx.translate(x, y); // Check line 63 >> I substituted the x,y values with locations
//identifying the color so that we can substitute in line 61
ctx.fillStyle = color;
// identifying radius
ctx.beginPath();
ctx.arc(0, 0, rad, 0, 2*Math.PI);
ctx.fill();
//restoring
ctx.restore();
}
كود تحريك المستطيل
كما نشاهد في الصورة ،، المستطيل يتحرك بشكل أفقي، بحيث تعتمد الحركة على الموقع بالنسبة لـ X وسرعته:
وبالمتغيرات التي عرفتها سابقا: var recX = 10; var speed = 1;
ستكون قاعدة التحريك كالآتي:
recX = rexX + speed
أو recX += speed
بالنسبة لتصادم المستطيل مع حوائط الcanvas ، دعوننا نعبر عنها بشكل رياضي ليسهل علينا تحويلها إلى كود… حيث أنه مرتبط باتجاه سرعة المستطيل عند كل طرف
الcanvas يتم رسمه من اليسار إلى اليمين كما شاهدنا في الصورة أعلاه، حيث أن الحائط الرأسي الأيسر = صفر
والأيمن = canvas.width
الآن نستطيع تحديد موقع الأشكال داخل الصندوق
موقع المستطيل في X وطوله أيضا > 0 (أي على يمين ضلع الcanvas الأيسر)
موقع المستطيل في X وطوله أيضا < w (أقل من canvas.width أي على يسار ضلع الcanvas الأيمن)
اذا استخدمنا if conditional ، يمكننا عمل شروط تحدد اتجاه السرعة للمستطيل كالتالي:
if (((recX + rectWidth) > w) || (recX < 0)) {
speed = -speed; //speed direction changes!
}
هنا نشترط أنه اذا خرج موقع X أو طوله عن الضلع الأيمن فيتغير اتجاه السرعة الي اليسار،، واذا خرج طول المستطيل عن الضلع الايسر فيتغير اتجاه السرعة الى اليمين
كود تحريك الدائرة
نطبق نفس الفكرة على الدائرة … ونريدها ايضا تسير في الاتجاه y مع x >> الكود كالتالي:
// I made the movement in x and y directions
cirx += spx;
ciry += spy;
//collision with walls
// 1. vertical walls --> right wall
if ((cirx + rad) > canvas.width) {
spx = -spx;
cirx = w - rad; //putting ball at collision point
} else if ((cirx - rad) < 0) {
spx = -spx;
cirx = rad; //putting ball at collision point
}
// 2. horizontal walls --> right one
if ((ciry + rad) > canvas.height) {
spy = -spy;
ciry = h - rad;
} else if ((ciry - rad) < 0) {
spy = -spy;
ciry = rad;
}
}
لقد نشرت الشرح بالفيديو على جروب اسرة المبادرة على الفيسبوك من هنا: https://www.facebook.com/groups/1793719174001339/permalink/1883387115034544/
آسف على طول الشرح… وأرجو أن يكون مفهوما…