M.M.Norouzi
M.M.Norouzi
خواندن ۳ دقیقه·۲ سال پیش

موتورهای بازی سازی چگونه کار میکنند؟ (قسمت ۱)

سلام . من محمد مهدی نوروزی قصد دارم با سازوکار های موتورهای بازی سازی و گرافیکی بیشتر آشنا بشم.پس تصمیم گرفتم بشینم و مثل یک پسر خوب یک کتاب انتخاب کنم و بخونمش تا با مسایل گوناگون موجود در دنیای گرافیکی و ۲بعدی و ۳بعدی بیشتر آشنا بشم.این کار رو فعلاً برای سرگرمی انجامش میدم و محرکم که سرچشمه این حرکت شد که برم سراغ این چنین مسایلی چیزی نبود جز metaverse.


تصمیم گرفتم هروقت بخشی از کتاب رو خوندم بیام و درس پس بدم.قول نمیدم هر شب یا به طور منظم این اتفاق بیوفته ولی همه تلاشمو میکنم به طور منظم پیش برم و چیزای جدیدی رو که یاد میگیرم به اشتراک بگذارم.

اولین مطلب آشنایی با بردارهاست.یک بردار جهت و اندازه داره به شکلی که اگر دو بردار جهت و اندازه یکسان داشته باشن پس با هم برابرن.برای نمایش بردارها از دستگاه‌های مختصات مختلف میشه استفاده کرد.ما از دستگاه معروف کارتزینکه از قبل هم باهاش آشناییم و میدونیم سه جهت x , y , z رو داره استفاده خواهیم کرد.

بردار ها میتونن ابعاد زیادی داشته باشن.برای مثال بردار زیر رو فرض میکنیم

v = ( v1 , v2 , … , vn)

در بردار بالا ما n بعد داریم.و مقدار مربوط به هر بعد رو میتونیم به vi که اینجا منظور

از i شماره بعد هست نسبت بدیم.

از اونجایی که میخوایم دنیای ۲ بعدی و ۳ بعدی رو شبیه سازی کنیم پس نیاز داریم بردارهای ۲بعدی و ۳بعدی رو تعریف کنیم.

من برای پیاده‌سازی بردارها از زبان برنامه نویسی rust استفاده میکنم.

ابتدا یک پروژه جدید رو آغاز میکنم:

cargo new wmb

همچنین نیازه که کتابخانه rand رو به پروژه اضافه کنیم:

cargo add rand

و شروع میکنم به تعریف کردن بردارها:

برای بردارهای ۲بعدی و ۳بعدی به ترتیب فایل‌های vector2d و vector3d رو ایجاد میکنم.

کدهای زیر رو داخل فایل vector2d مینویسیم:

pub struct Vector2D {
x: f32,
y: f32,
}


impl From<(f32, f32)> for Vector2D {
fn from(tup: (f32, f32)) -> Self {
Self { x: tup.0, y: tup.1 }
}
}


impl From<&[f32; 2]> for Vector2D {
fn from(arr: &[f32; 2]) -> Self {
Self {
x: arr[0],
y: arr[1],
}
}
}


impl From<[f32; 2]> for Vector2D {
fn from(arr: [f32; 2]) -> Self {
Self {
x: arr[0],
y: arr[1],
}
}
}


impl Default for Vector2D {
fn default() -> Self {
Self {
x: Default::default(),
y: Default::default(),
}
}
}


impl Vector2D {
pub fn create(x: f32, y: f32) -> Self {
Self { x, y }
}
}


#[cfg(test)]
mod tests {
use super::*;
use rand::Rng;
#[test]
fn create_test() {
let mut rng = rand::thread_rng();
let x = rng.gen::<f32>();
let y = rng.gen::<f32>();
let vec = Vector2D::create(x, y);
assert_eq!(x, vec.x);
assert_eq!(y, vec.y);
}
#[test]
fn from_tup_test() {
let mut rng = rand::thread_rng();
let x = rng.gen::<f32>();
let y = rng.gen::<f32>();
let vec: Vector2D = (x, y).into();
assert_eq!(x, vec.x);
assert_eq!(y, vec.y);
}
#[test]
fn from_arr_borrowed_test() {
let mut rng = rand::thread_rng();
let x = rng.gen::<f32>();
let y = rng.gen::<f32>();
let vec: Vector2D = (&[x, y]).into();
assert_eq!(x, vec.x);
assert_eq!(y, vec.y);
}
#[test]
fn from_arr_owned_test() {
let mut rng = rand::thread_rng();
let x = rng.gen::<f32>();
let y = rng.gen::<f32>();
let vec: Vector2D = [x, y].into();
assert_eq!(x, vec.x);
assert_eq!(y, vec.y);
}
}

همچنین برای پیاده‌سازی Vector3D میتونیم از کدهای Vector2D استفاده کنیم به

شکلی که یک بعد z به تعریف اصلی اضافه میشه و همچنین باید هنگام تبدیلات و

تست ها بعد جدید رو درگیر کنیم.

این کار رو به شما میسپارم.

گیتهاب پروژه

کانال تلگرام

عضویت تو کانال تلگرامی به شما کمک میکنه خیلی زودتر به مطالب دست پیدا کنید و همچنین میتونید سوالاتونو از اون طریق بپرسید.

کاری از محمد مهدی نوروزی

برنامه نویسیبازی سازیمحاسبات برداریآموزش rustmuhammad mahdi norouzi
.NET Developer
شاید از این پست‌ها خوشتان بیاید