Learn Rust Coding · درس

التعامل مع الإدخال والوقت

استجب للاعب وللساعة

الدرس 3 من 413 خطوة

التعامل مع الإدخال والوقت درس مجاني في Learn Rust Coding على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Learn Rust Coding، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Learn Rust Coding 4 دروس في المجموع.

الإدخال كمورد

توجد حالة لوحة المفاتيح في مورد ButtonInput<KeyCode> الذي يوفره DefaultPlugins.

اطلبوه للقراءة فقط باستخدام Res. يحدّثه Bevy في كل إطار قبل تشغيل أنظمتكم، لذلك ترون دائمًا الحالة الحالية.

fn read_keys(keys: Res<ButtonInput<KeyCode>>) {
    if keys.pressed(KeyCode::Space) {
        info!("space held");
    }
}

pressed مقابل just_pressed

تكون pressed صحيحة في كل إطار يبقى فيه المفتاح مضغوطًا، وهي مناسبة للحركة المستمرة. أما just_pressed فتكون صحيحة فقط في الإطار الذي يُضغط فيه المفتاح.

استخدموا just_pressed للإجراءات المتقطعة مثل القفز أو إطلاق النار، حتى تؤدي الضغطة الواحدة الإجراء مرة واحدة.

fn jump(keys: Res<ButtonInput<KeyCode>>) {
    if keys.just_pressed(KeyCode::ArrowUp) {
        info!("jump!");
    }
}

إنشاء متجه الاتجاه

ادمجوا عدة مفاتيح في اتجاه للحركة. ابدؤوا من الصفر وأضيفوا وحدة على كل محور لكل مفتاح مضغوط.

تمنع تسوية النتيجة الحركة القطرية من أن تكون أسرع من الحركة المستقيمة.

fn direction(keys: Res<ButtonInput<KeyCode>>) -> Vec2 {
    let mut d = Vec2::ZERO;
    if keys.pressed(KeyCode::KeyW) { d.y += 1.0; }
    if keys.pressed(KeyCode::KeyS) { d.y -= 1.0; }
    if keys.pressed(KeyCode::KeyA) { d.x -= 1.0; }
    if keys.pressed(KeyCode::KeyD) { d.x += 1.0; }
    d.normalize_or_zero()
}

مورد الزمن

تختلف معدلات الإطارات باختلاف الأجهزة، لذا لا تحرّكوا العناصر بمقدار ثابت في كل إطار. يمنحكم مورد Time الدالة delta_secs()، وهي عدد الثواني منذ الإطار السابق.

يؤدي ضرب السرعة في دلتا الزمن إلى جعل الحركة مستقلة عن معدل الإطارات.

fn move_player(time: Res<Time>, mut q: Query<&mut Transform, With<Player>>) {
    let dt = time.delta_secs();
    for mut tf in &mut q {
        tf.translation.x += 200.0 * dt;
    }
}

دمج الإدخال والزمن

يجمع النمط الفعلي بين الموردين في نظام واحد: اقرأوا الاتجاه من الإدخال، ثم اضربوه في السرعة ودلتا الزمن.

ينتج عن ذلك تحكم سلس ومتسق، سواء عملت اللعبة بمعدل 30 إطارًا في الثانية أو 144 إطارًا في الثانية.

fn drive(
    keys: Res<ButtonInput<KeyCode>>,
    time: Res<Time>,
    mut q: Query<&mut Transform, With<Player>>,
) {
    let mut d = Vec2::ZERO;
    if keys.pressed(KeyCode::KeyA) { d.x -= 1.0; }
    if keys.pressed(KeyCode::KeyD) { d.x += 1.0; }
    let step = d.normalize_or_zero() * 300.0 * time.delta_secs();
    for mut tf in &mut q {
        tf.translation += step.extend(0.0);
    }
}

أزرار الفأرة

تستخدم أزرار الفأرة واجهة ButtonInput نفسها، مع MouseButton بدلًا من KeyCode.

يعني هذا الاتساق أن عادات استخدام pressed وjust_pressed التي اكتسبتموها مع لوحة المفاتيح تنتقل مباشرةً إلى النقرات.

fn shoot(buttons: Res<ButtonInput<MouseButton>>) {
    if buttons.just_pressed(MouseButton::Left) {
        info!("fire");
    }
}

المؤقتات لفترات الانتظار

يتتبع Timer الزمن المنقضي باتجاه مدة مستهدفة. حدّثوه باستخدام دلتا الإطار في كل عملية تحديث.

استخدموا مؤقتًا متكررًا لتحديد وتيرة إطلاق النار، وتحققوا من just_finished() لمعرفة وقت تنفيذ الإجراء.

#[derive(Component)]
struct Cooldown(Timer);

fn tick(time: Res<Time>, mut q: Query<&mut Cooldown>) {
    for mut cd in &mut q {
        cd.0.tick(time.delta());
        if cd.0.just_finished() { info!("ready"); }
    }
}

إنشاء مؤقت

أنشئوا مؤقتًا من مدة ومن TimerMode. يتوقف Once بعد إطلاقه، بينما يُعاد ضبط Repeating تلقائيًا.

خزّنوه في مكوّن حتى يتمكن كل كيان، مثل المدفع، من امتلاك وتيرته المستقلة.

use std::time::Duration;

commands.spawn((
    Turret,
    Cooldown(Timer::new(Duration::from_millis(500), TimerMode::Repeating)),
));

استخدام FixedUpdate للحتمية

غالبًا ما تحتاج الفيزياء وشبكات اللعب إلى خطوة زمنية ثابتة. تعمل الأنظمة في جدول FixedUpdate عددًا ثابتًا من المرات في الثانية، بغض النظر عن معدل العرض.

استخدموا داخلها Time<Fixed>، إذ تكون دلتا الزمن فيه ثابتة دائمًا، مما يمنحكم محاكاة قابلة لإعادة الإنتاج.

App::new()
    .add_plugins(DefaultPlugins)
    .add_systems(FixedUpdate, physics_step)
    .run();

الزمن المنقضي مقابل دلتا الزمن

يمثل time.delta_secs() الفاصل منذ الإطار السابق، بينما يمثل time.elapsed_secs() إجمالي الزمن منذ بدء التشغيل.

يُعد الزمن المنقضي مناسبًا للرسوم المتحركة التي تقودها موجة جيبية، مثل عنصر قابل للجمع يتمايل، حيث تُمرَّر المدة الكلية إلى الدالة.

fn bob(time: Res<Time>, mut q: Query<&mut Transform, With<Pickup>>) {
    let t = time.elapsed_secs();
    for mut tf in &mut q {
        tf.translation.y = (t * 2.0).sin() * 10.0;
    }
}

تقييد الحدود

بعد الحركة، أبقوا اللاعب داخل الشاشة بتقييد التحويل ضمن أنصاف أبعاد النافذة.

تقيّد f32::clamp كل محور ضمن حدوده. اقرأوا حجم النافذة من استعلام Window عند الحاجة إلى حدود دقيقة.

fn clamp(mut q: Query<&mut Transform, With<Player>>) {
    for mut tf in &mut q {
        tf.translation.x = tf.translation.x.clamp(-300.0, 300.0);
        tf.translation.y = tf.translation.y.clamp(-200.0, 200.0);
    }
}

تحقّق سريع

فكّروا في استقلال الحركة عن معدل الإطارات.

مراجعة: الإدخال والزمن

يوجد الإدخال في موارد ButtonInput؛ استخدموا pressed للإجراءات المستمرة أثناء الضغط، وjust_pressed للنقرات. يحافظ مورد Time ومكوّنات Timer على استقلال الحركة وفترات الانتظار عن معدل الإطارات.

بعد إتمام التحكم، سيضيف الدرس الأخير التصادمات وانتقالات حالة اللعبة.

البدء مجانًا

تعلم Rust مع معلم ذكاء اصطناعي — مجانًا

اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.

الدورات
39
الدروس
144

الأسئلة الشائعة

هل درس «التعامل مع الإدخال والوقت» مجاني؟

نعم — نص درس «التعامل مع الإدخال والوقت» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Learn Rust Coding، انتقل إلى CoddyKit PRO. تتضمن دورة Learn Rust Coding 4 دروس في المجموع.

ماذا ستتعلم في «التعامل مع الإدخال والوقت»؟

استجب للاعب وللساعة تتمرن على Learn Rust Coding مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Learn Rust Coding؟

لا تُشترط خبرة سابقة. Learn Rust Coding على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «التعامل مع الإدخال والوقت»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Learn Rust Coding هذا؟

نعم. كل درس في Learn Rust Coding يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. عقلية ECS
  2. إنشاء الكيانات وتحريكها
  3. التعامل مع الإدخال والوقت
  4. التصادمات وحالة اللعبة
← العودة إلى Learn Rust Coding