الحركة والتحكم
تعلم كيفية إضافة حركة سلسة للاعب والتحكم به باستخدام لوحة المفاتيح.
مقدمة في التحكم باللاعب
التحكم باللاعب هو أحد أهم عناصر تجربة اللعب. في هذا الدرس، سنتعلم كيفية:
- الاستماع لأحداث لوحة المفاتيح
- تحديث موقع اللاعب بناءً على الإدخال
- إضافة تسارع وسرعة قصوى للحركة
- جعل الحركة أكثر سلاسة باستخدام التداخل (interpolation)
💡 لماذا نستخدم نظام السرعة بدلاً من التحرك بخطوات ثابتة؟
استخدام نظام السرعة يجعل الحركة أكثر سلاسة ويتيح لنا إضافة تأثيرات مثل التسارع والاحتكاك، مما يجعل التحكم باللعبة يشعر بأنه أكثر استجابة وواقعية.
مثال تفاعلي: تحريك اللاعب
جرب تحريك المربع الأزرق باستخدام مفاتيح الأسهم أو WASD:
السرعة: 0, 0
الموقع: 0, 0
الحالة: ساكن
مفاتيح الأسهم
↑
←
↓
→
مفاتيح WASD
W
A
S
D
كود التحكم باللاعب
هذا الكود يوضح كيفية تنفيذ نظام الحركة:
// حالة اللاعب
const player = {
x: 400,
y: 200,
width: 40,
height: 40,
speed: 200, // سرعة الحركة (بكسل في الثانية)
vx: 0, // السرعة الأفقية
vy: 0, // السرعة الرأسية
ax: 0, // التسارع الأفقي
ay: 0 // التسارع الرأسي
};
// كائن لتتبع المفاتيح المضغوطة
const keys = {
ArrowUp: false,
ArrowDown: false,
ArrowLeft: false,
ArrowRight: false,
w: false,
a: false,
s: false,
d: false
};
// الاستماع لأحداث لوحة المفاتيح
window.addEventListener('keydown', (e) => {
if (keys.hasOwnProperty(e.key)) {
keys[e.key] = true;
e.preventDefault();
}
});
window.addEventListener('keyup', (e) => {
if (keys.hasOwnProperty(e.key)) {
keys[e.key] = false;
e.preventDefault();
}
});
// تحديث حالة اللاعب
function updatePlayer(deltaTime) {
// إعادة تعيين التسارع
player.ax = 0;
player.ay = 0;
// تحديث التسارع بناءً على المفاتيح المضغوطة
if (keys.ArrowUp || keys.w) player.ay -= 1;
if (keys.ArrowDown || keys.s) player.ay += 1;
if (keys.ArrowLeft || keys.a) player.ax -= 1;
if (keys.ArrowRight || keys.d) player.ax += 1;
// تطبيق التسارع على السرعة
if (player.ax !== 0 || player.ay !== 0) {
// تطبيع المتجه للحفاظ على سرعة ثابتة في جميع الاتجاهات
const length = Math.sqrt(player.ax * player.ax + player.ay * player.ay);
player.ax = (player.ax / length) * player.speed;
player.ay = (player.ay / length) * player.speed;
// تطبيق السرعة مع مراعاة الوقت المنقضي
player.vx = player.ax;
player.vy = player.ay;
} else {
// تطبيق الاحتكاك عند عدم الضغط على أي مفتاح
player.vx *= 0.9;
player.vy *= 0.9;
// إيقاف الحركة عندما تكون السرعة صغيرة جدًا
if (Math.abs(player.vx) < 0.1) player.vx = 0;
if (Math.abs(player.vy) < 0.1) player.vy = 0;
}
// تحديث الموقع
player.x += player.vx * (deltaTime / 1000);
player.y += player.vy * (deltaTime / 1000);
// منع اللاعب من الخروج من حدود الشاشة
player.x = Math.max(0, Math.min(canvas.width - player.width, player.x));
player.y = Math.max(0, Math.min(canvas.height - player.height, player.y));
}
// دالة الرسم
function drawPlayer() {
ctx.fillStyle = '#4f46e5';
ctx.fillRect(player.x, player.y, player.width, player.height);
}
// دالة التحديث الرئيسية
function update(deltaTime) {
updatePlayer(deltaTime);
}
// دالة الرسم الرئيسية
function draw() {
// مسح الشاشة
ctx.clearRect(0, 0, canvas.width, canvas.height);
// رسم الخلفية
ctx.fillStyle = '#f8fafc';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// رسم اللاعب
drawPlayer();
// رسم معلومات التصحيح
drawDebugInfo();
}
// حلقة اللعبة
let lastTime = 0;
function gameLoop(timestamp) {
const deltaTime = timestamp - lastTime;
lastTime = timestamp;
update(deltaTime);
draw();
requestAnimationFrame(gameLoop);
}
// بدء اللعبة
requestAnimationFrame(gameLoop);
أنماط الحركة المختلفة
1. الحركة الفورية
يتحرك اللاعب فورًا إلى الموقع الجديد بدون تسارع أو احتكاك.
if (keys.ArrowRight) player.x += speed;
if (keys.ArrowLeft) player.x -= speed;
if (keys.ArrowUp) player.y -= speed;
if (keys.ArrowDown) player.y += speed;
2. الحركة مع تسارع
يتسارع اللاعب تدريجيًا عند الضغط على المفاتيح.
// تسريع
if (keys.ArrowRight) player.vx += acceleration;
if (keys.ArrowLeft) player.vx -= acceleration;
// تطبيق السرعة
player.x += player.vx;
// تطبيق الاحتكاك
player.vx *= friction;
3. الحركة المتجهية
يتم حساب السرعة باستخدام المتجهات للحركة في أي اتجاه.
// حساب متجه السرعة
const angle = Math.atan2(targetY - player.y, targetX - player.x);
player.vx = Math.cos(angle) * speed;
player.vy = Math.sin(angle) * speed;
// تحديث الموقع
player.x += player.vx;
player.y += player.vy;
نصائح لتحسين تجربة التحكم
💡 نصائح مهمة:
- استخدم
deltaTimeلجعل الحركة مستقرة بغض النظر عن معدل الإطارات. - أضف تسارعًا تدريجيًا للحركة بدلاً من التحرك الفوري.
- استخدم الاحتكاك لجعل الحركة أكثر واقعية.
- أضف تأثيرات بصرية عند الحركة (مثل انحراف الكاميرا قليلاً).
- تحقق من التصادمات بعد تحديث الموقع.
ما التالي؟
الآن بعد أن تعلمت كيفية إضافة حركة سلسة للاعب، يمكنك الانتقال إلى الدرس التالي حيث سنتعلم كيفية إضافة الفيزياء الأساسية مثل الجاذبية والقفز.