2017-02-21 1 views
1

Ich versuche, etwas Spielprogrammierung mit Piston zu machen, aber ich habe Probleme mit opengl_graphics::Texture, da es keine Copy oder Clone ableitet.Wie kopiere/klone ich eine Struktur, die keine davon ableitet?

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) {} 
} 

Das Hauptspiel Schleife:

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); 
     } 
    } 
} 

den Fehler produziert:

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` 

Ich verstehe, warum ich diesen Fehler, da opengl_graphics::Texture nicht Copy herleiten kann ich nicht Klon Option<opengl_texture>. Welche Abhilfe gibt es dafür?

Ich habe versucht, mit Referenzen herumspielen, aber das hat nicht funktioniert.

+1

Wie wäre es direkt einen 'Rc ' statt 'Tex' mit ? – kennytm

+0

@kennytm Soll ich mein temporäres Sprite 'spr' 'Rc ' machen? Ich bin immer noch ein bisschen Neuling in Rust, also habe ich 'Rc' nie benutzt (siehe Dokumentation). –

+0

@DavidFrickert Leider muss 'game.player.sprite' auch' Rc 'sein, da es nur eine Kopie von' Tex' geben kann. Ja, sobald du 'Rc' gehst, wird es überall gebraucht, wo es hinkommt. – kennytm

Antwort

4

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

Sie nicht. Das einzige, was Sie tun können, ist einen Hinweis darauf zu nehmen.


In diesem Fall ist es eine sehr gute Sache, dass die Bibliothek ausgewählt hat Clone oder Copy nicht zu implementieren. Wenn Sie die Struktur klonen könnten, würden Sie häufig und unnötigerweise viel Speicher zuweisen. Stattdessen hat Sie die Bibliothek gezwungen, darüber nachzudenken, wann Sie diesen Speicher reservieren. Eine der Lösungen ist es, alle Texturen beim Start der Anwendung zu laden und auf sie verweisen:

Ihre Strukturen ändern Referenzen zu halten:

#[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, 
} 

laden die früh Texturen in main. Beachten Sie, dass es keine Notwendigkeit Path explizit zu verwenden, wie es AsRef<Path> nimmt:

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() 
}; 

Dann Verweise auf diese Texturen passieren:

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; 
     } 
    } 
} 

Beachten Sie, dass dies auch die Orte, konsolidiert, die Fehler auftreten können. Es gibt keine unwrap innerhalb der Eingeweide der Schleife.


Ich war nicht in der Lage, Ihren Code zu erhalten Kompilierung zu beenden, da der Code nicht vollständig ist, aber dies sollte beim Starten helfen:

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

Danke für die tolle Antwort! Ich habe das 'impl Game' hinzugefügt, das verpasst hat. Mittlerweile bin ich mit 'Rc' beschäftigt, aber ich habe einen seltsamen Fehler, irgendwie findet' Path' meine Bilder nicht mehr. –

+0

Also, wenn Sie mich nicht fragen, was wäre effizienter: 'Rc' oder Referenzen? Die Art und Weise angewendet I 'Rc ' beteiligt Klonen: 'lassen mut spr: Rc = game.player.sprite.clone()' und 'game.player.sprite = spr.clone()', aber Referenzen müssen nicht Klonen, so würde ich vermuten, dass Referenzen besser sind. Obwohl ich 'Rc' falsch gebrauchen könnte. –

+0

Übrigens (es tut mir leid, dass ich dich so sehr belästige!), Tatsächlich habe ich die 'struct Position' nicht erstellt, ich glaube, ich habe sie wegen eines meiner 'Use's (i denken 'piston_window'. kann ich ein 'struct erstellen Position'and außer Kraft setzen the one? –

Verwandte Themen