سلام . من محمد مهدی نوروزی قصد دارم با سازوکار های موتورهای بازی سازی و گرافیکی بیشتر آشنا بشم.پس تصمیم گرفتم بشینم و مثل یک پسر خوب یک کتاب انتخاب کنم و بخونمش تا با مسایل گوناگون موجود در دنیای گرافیکی و ۲بعدی و ۳بعدی بیشتر آشنا بشم.این کار رو فعلاً برای سرگرمی انجامش میدم و محرکم که سرچشمه این حرکت شد که برم سراغ این چنین مسایلی چیزی نبود جز 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 به تعریف اصلی اضافه میشه و همچنین باید هنگام تبدیلات و
تست ها بعد جدید رو درگیر کنیم.
این کار رو به شما میسپارم.
عضویت تو کانال تلگرامی به شما کمک میکنه خیلی زودتر به مطالب دست پیدا کنید و همچنین میتونید سوالاتونو از اون طریق بپرسید.
کاری از محمد مهدی نوروزی