如何复制/克隆一个既不派生又不派生的结构?

Dav*_*ert 5 rust

我正在尝试用 Piston 进行一些游戏编程,但我正在努力解决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) {}
}
Run Code Online (Sandbox Code Playgroud)

主游戏循环:

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); 
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

产生错误:

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) {}
}
Run Code Online (Sandbox Code Playgroud)

我明白为什么会出现此错误,因为opengl_graphics::Texture没有导出Copy我无法克隆Option<opengl_texture>。有什么解决方法吗?

我尝试乱搞参考资料,但没有成功。

She*_*ter 4

如何复制/克隆一个既不派生又不派生的结构?

你不知道。您唯一能做的就是对其进行某种参考。


在这种情况下,图书馆选择不实现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,
}
Run Code Online (Sandbox Code Playgroud)

尽早加载纹理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()
};
Run Code Online (Sandbox Code Playgroud)

然后传递对这些纹理的引用:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这还合并了可能发生错误的位置。unwrap循环的内部不再存在。

我无法让您的代码完成编译,因为代码不完整,但这应该有助于开始:

#[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,
}
Run Code Online (Sandbox Code Playgroud)

在某些情况下,您可以将类型包装在Rcor中Arc并克隆它。克隆Rc/Arc只会增加引用计数器,无论底层类型的实现如何Clone(或不存在这样的实现)。