2017-02-21 36 views
1

Я пытаюсь сделать некоторые игры программирования с поршнем, но я борется с opengl_graphics::Texture, так как он не выводит Copy или Clone.Как скопировать/клонировать структуру, которая не выводит ни один из них?

extern crate piston_window; 
extern crate piston; 
extern crate graphics; 
extern crate opengl_graphics; 

use opengl_graphics::Texture as Tex; 
use piston_window::*; 
use std::path::Path; 
use opengl_graphics::GlGraphics; 

#[derive(PartialEq)] 
enum ObjectType { 
    Blocking, 
    Passing, 
} 
struct Object { 
    sprite: Tex, 
    obj_type: ObjectType, 
    position: Position, 
} 
struct Game { 
    gl: GlGraphics, 
    images: Vec<Object>, 
    player: Player, 
} 
struct Player { 
    sprite: Tex, 
    position: Position, 
} 
struct Position { 
    x: i32, 
    y: i32, 
} 

impl Game { 
    fn render(&mut self, args: &RenderArgs) { 

     let iter = self.images.iter(); 
     let player = &self.player; 
     self.gl.draw(args.viewport(), |c, g| { 

      clear([1.0, 1.0, 1.0, 1.0], g); 

      for img in iter { 
       let pos = img.get_position(); 
       let transform = c.transform.trans(((pos.x * 64)) as f64, ((pos.y * 64)) as f64); 
       image(img.get_sprite(), transform, g); 
      } 
      image(player.get_sprite(), 
        c.transform.trans((player.get_position().x * 64) as f64, 
            (player.get_position().y * 64) as f64), 
        g); 
     }); 
    } 


    fn update(&mut self, args: &UpdateArgs) {} 
} 

Основной цикл игры:

fn main() { 
    let (width, height) = (64*10, 64*10); 
    let opengl = OpenGL::V3_2; 
    let mut window: PistonWindow = 
     WindowSettings::new("piston", (width, height)) 
     .exit_on_esc(true) 
     .opengl(opengl) 
     .build() 
     .unwrap(); 
    window.hide(); 
    println!("Loading..."); 
    let mut player = Player { sprite: Tex::from_path(&Path::new(
          "./assets/player_n.png")).unwrap(), 
          position: Position { x: 3, y: 3 }, 
    }; 

    let mut game = Game { 
     gl: GlGraphics::new(opengl), 
     images: Vec::new(), 
     player: player, 
    }; 

    for i in 0..10 { 
     for j in 0..10 { 
      if i == 0 || i == 9 || j == 0 || j == 9 { 
       let obj = Object { sprite: Tex::from_path(&Path::new(
         "./assets/wall.png")).unwrap(),             
        obj_type: ObjectType::Blocking, 
         position: Position { x: i, y: j }, 
       }; 
       game.images.push(obj); 

      } else { 
       let obj = Object { sprite: Tex::from_path(&Path::new(
         "./assets/floor.png")).unwrap(),             
        obj_type: ObjectType::Passing, 
         position: Position { x: i, y: j }, 
       }; 
       game.images.push(obj); 
      } 
     } 
    } 
    window.show(); 
    while let Some(e) = window.next() { 

     if let Some(Button::Keyboard(key)) = e.press_args() { 
      let mut pos = game.player.position.clone(); 
      let mut spr: Option<Tex> = None;   
      match key { 
       Key::Up => { pos.y -= 1; spr = Some(Tex::from_path(&Path::new(
         "./assets/player_n.png")).unwrap()); }, 
       Key::Down => { pos.y += 1; spr = Some(Tex::from_path(&Path::new(
         "./assets/player_s.png")).unwrap()); }, 
       Key::Left => { pos.x -= 1; spr = Some(Tex::from_path(&Path::new(
         "./assets/player_w.png")).unwrap()); },    
       Key::Right => { pos.x += 1; spr = Some(Tex::from_path(&Path::new(
         "./assets/player_e.png")).unwrap()); }, 
       _ =>(), 
      } 
      for elem in game.images.iter() { 
       if pos.x == elem.position.x && pos.y == elem.position.y && elem.obj_type == ObjectType::Passing { 
        game.player.position = pos; 

        game.player.sprite = spr.clone().unwrap(); 

       } 
      } 
     }   
     if let Some(r) = e.render_args() { 
      game.render(&r);  
     } 
     if let Some(u) = e.update_args() { 
      game.update(&u); 
     } 
    } 
} 

Выдает ошибку:

error: no method named `clone` found for type `std::option::Option<opengl_graphics::Texture>` in the current scope 
    --> src/main.rs:159:46 
159 |      game.player.sprite = spr.clone().unwrap(); 
    |            ^^^^^ 
    | 
    = note: the method `clone` exists but the following trait bounds were not satisfied: `opengl_graphics::Texture : std::clone::Clone` 

Я понимаю, почему я получаю эту ошибку, так как opengl_graphics::Texture не выводит Copy я не могу клонировать Option<opengl_texture>. Какое обходное решение для этого?

Я попытался возиться со ссылками, но это не сработало.

+1

Как об использовании '' Rc вместо 'Tex' напрямую ? – kennytm

+0

@kennytm Должен ли я сделать свой временный спрайт 'spr' 'Rc '? Я все еще немного новичок в Rust, поэтому я никогда не использовал 'Rc' (смотри документы). –

+0

@DavidFrickert К сожалению, 'game.player.sprite' также должен быть' Rc ', потому что может быть только одна копия простого 'Tex'. Да, как только вы зайдете на «Rc», он будет нужен везде, где он будет касаться. – kennytm

ответ

4

How do I copy/clone a struct that derives neither?

У вас нет. Единственное, что вы можете сделать, это взять какую-то ссылку на него.


В этом случае, это очень хорошо, что библиотека выбрала не реализует Clone или Copy. Если вы смогли клонировать структуру, вы бы часто и много раз выделяли много памяти. Вместо этого библиотека заставила вас задуматься о том, когда вы выделите эту память. Одним из решений является для загрузки всех текстур при запуске приложения и ссылки на них:

Измените структуры для хранения ссылок:

#[derive(PartialEq)] 
enum ObjectType { 
    Blocking, 
    Passing, 
} 

struct Object<'a> { 
    sprite: &'a Tex, 
    obj_type: ObjectType, 
    position: Position, 
} 

struct Game<'a> { 
    gl: GlGraphics, 
    images: Vec<Object<'a>>, 
    player: Player<'a>, 
} 

struct Player<'a> { 
    sprite: &'a Tex, 
    position: Position, 
} 

#[derive(Copy, Clone, PartialEq)] 
struct Position { 
    x: i32, 
    y: i32, 
} 

struct Textures { 
    player_n: Tex, 
    player_s: Tex, 
    player_e: Tex, 
    player_w: Tex, 
    wall: Tex, 
    floor: Tex, 
} 

загрузки текстур на ранних стадиях main. Обратите внимание, что нет необходимости использовать Path в явном виде, как он принимает AsRef<Path>:

let textures = Textures { 
    player_n: Tex::from_path("./assets/player_n.png").unwrap(), 
    player_s: Tex::from_path("./assets/player_s.png").unwrap(), 
    player_e: Tex::from_path("./assets/player_e.png").unwrap(), 
    player_w: Tex::from_path("./assets/player_w.png").unwrap(), 
    wall: Tex::from_path("./assets/wall.png").unwrap(), 
    floor: Tex::from_path("./assets/floor.png").unwrap() 
}; 

Затем передать ссылки на эти текстуры:

match key { 
    Key::Up => { 
     pos.y -= 1; 
     spr = Some(&textures.player_n) 
    } 
    Key::Down => { 
     pos.y += 1; 
     spr = Some(&textures.player_s) 
    } 
    Key::Left => { 
     pos.x -= 1; 
     spr = Some(&textures.player_w) 
    } 
    Key::Right => { 
     pos.x += 1; 
     spr = Some(&textures.player_e) 
    } 
    _ =>(), 
} 
for elem in game.images.iter() { 
    if pos == elem.position && elem.obj_type == ObjectType::Passing { 
     game.player.position = pos; 

     if let Some(spr) = spr { 
      game.player.sprite = spr; 
     } 
    } 
} 

Обратите внимание, что это также объединяет места, которые могут возникнуть ошибки. Внутри кишки петли больше нет unwrap.


Мне не удалось получить код для окончания компиляции в код не является полным, но это должно помочь начать:

error: no method named `render` found for type `Game<'_>` in the current scope 
    --> src/main.rs:122:18 
    | 
122 |    game.render(&r); 
    |     ^^^^^^ 
    | 
    = help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `render`, perhaps you need to implement it: 
    = help: candidate #1: `piston_window::RenderEvent` 

error: no method named `update` found for type `Game<'_>` in the current scope 
    --> src/main.rs:125:18 
    | 
125 |    game.update(&u); 
    |     ^^^^^^ 
    | 
    = help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item `update`, perhaps you need to implement one of them: 
    = help: candidate #1: `piston_window::UpdateEvent` 
    = help: candidate #2: `piston_window::<unnamed>::UpdateTexture` 
    = help: candidate #3: `deflate::checksum::RollingChecksum` 
    = help: candidate #4: `cocoa::appkit::NSOpenGLContext` 
    = help: candidate #5: `cocoa::appkit::NSOpenGLContext` 
+0

Спасибо за отличный ответ! Я добавил пропущенную игру 'impl Game'. Тем временем я возился с «Rc», но у меня какая-то странная ошибка, так как «Путь» больше не находит мои изображения. –

+0

Итак, если вы не возражаете, я спрашиваю, что было бы более эффективным: «Rc» или ссылки? Способ, которым я применил 'Rc ' участие клонирования: 'let mut spr: Rc = game.player.sprite.clone()' и 'game.player.sprite = spr.clone()', но ссылки не нужны клонирование, поэтому я бы предположил, что ссылки лучше. Хотя я могу использовать «Rc» неправильно. –

+0

Кстати, извините, я вас так беспокою!), На самом деле, я не создал «struct Position», я думаю, что я включил его из-за одного из моих «use» (i подумайте 'piston_window'. Могу ли я создать« позицию структуры »и переопределить включенную? –