2009-05-26 3 views
5

Tôi có Tile s đại diện cho các ô trong thế giới 2 chiều của trò chơi. Các viên gạch có thể có các bức tường trên bất kỳ số nào của 4 mặt của chúng. Tôi có một cái gì đó như thế này vào lúc này:Cách hay để thực hiện điều này bằng ngôn ngữ OO C hiện đại?

interface Tile { 
    boolean isWallAtTop(); 
    boolean isWallAtRight(); 
    boolean isWallAtLeft(); 
    boolean isWallAtBottom(); 
} 

Một nơi khác tôi cũng có 16 hình ảnh, một cho mỗi cấu hình tường gạch có thể. Một cái gì đó như thế này:

static final Image WALLS_ALL_AROUND = ... 
static final Image WALL_ON_TOP_AND_RIGHT = ... 
/* etc etc all 16 possibilities */ 

Tôi muốn viết một

static Image getWallImage(Tile tile) 

Những gì tôi muốn tránh là sự tra tấn đi qua các khả năng như

if (tile.isWallTop && tile.isWallRight 
    && !tile.isWallBottom && !tile.isWallLeft) { 
    return WALL_ON_TOP_AND_RIGHT; 
} 

Có ai biết một cách dễ thương hơn để làm điều này?

Trả lời

15

Đi tiện ích bitmap. Sử dụng mặt nạ 4 bit cho mỗi ô, cho biết mặt nào có tường.

A B C D 

Bit A biểu thị một bức tường ở trên cùng, B bên phải, C phía dưới, D bên trái. Xác định các hằng số để giúp bạn rằng bạn chỉ có thể giao hợp một cách hợp lý với mặt nạ, tức là

if (tile.Walls & (WALL_LEFT | WALL_RIGHT)) 
    // Do stuff 

Để tìm hình ảnh, mặt nạ 4 bit này tạo ra 16 khả năng. Sử dụng nó như là một chỉ mục thành một hình ảnh "mảng", vì vậy bạn có thể trực tiếp tìm thấy hình ảnh chính xác mà không cần bất kỳ nỗ lực.

+0

OMG! Tôi đề nghị rằng các phương thức (hoặc Properties trong C#) được sử dụng, không phải các kiểm tra thủ công như "if (tile.Walls & (WALL_LEFT | WALL_RIGHT)). Phương pháp thủ công thêm các chi tiết không cần thiết vào mã của bạn. Tất nhiên, bình luận này không chống lại phương pháp 4-bit – jrharshath

+5

Mặt nạ bit là IMO là giải pháp sai ở đây (và thường là một hack xấu xí) Mã của OP hoàn toàn là thủ tục và anh ta yêu cầu một giải pháp OO –

+0

Bitmask là một sử dụng chúng, nhưng viết các biến vị ngữ mà bạn muốn như các phương thức tĩnh (mà JIT sẵn sàng, sẽ nội tuyến) – plinth

0

Bạn không thể làm điều gì đó với enums cờ?

0

Bạn nên đặt cấu hình tường thành một biến duy nhất và tạo bản đồ biến này cho hình ảnh xếp kề.

4

Các đối tượng ô có bất kỳ thuộc tính nào khác không? Nếu không (hoặc nếu bạn có thể phát hiện ra chúng), bạn có thể tự tạo các đối tượng ngói thành một liệt kê 16 hằng số với phương thức Tile.getImage() trả về một hình ảnh cố định được truyền cho hàm tạo. Đây được gọi là Flyweight pattern:

class Tile { 
    public final boolean isWallAtTop; 
    public final boolean isWallAtRight; 
    public final boolean isWallAtLeft; 
    public final boolean isWallAtBottom; 
    public final Image image; 

    private Tile(boolean top, boolean right, boolean left, 
       boolean bottom, Image image) 
    { 
     this.isWallAtTop = top; 
     this.isWallAtRight = right; 
     this.isWallAtLeft = left; 
     this.isWallAtBottom = bottom; 
     this.image = image; 
    } 

    public static final Tile WALLS_ALL_AROUND = 
     new Tile(true, true, true, true, new Image("allWalls.png")) 
    // more constants here, plus other methods that work with 
    // only the wall data 
} 

Trong Java, bạn có thể thậm chí thực hiện điều này như một enum "thực".

Đối với bản đồ bao gồm các ô, bạn có thể có mảng tham chiếu Ngói 2 chiều đơn giản hoặc nếu bạn cần dữ liệu khác cho từng ô riêng lẻ, hãy có một lớp khác có chứa "dữ liệu khác" và tham chiếu đến một trong các đối tượng Tile ở trên.

+0

Thậm chí tốt hơn sau khi chỉnh sửa. +2 từ tôi nếu có thể :) – willcodejavaforfood

2

Tôi khuyên bạn nên tạo một chút cờ enum như sau.

[Flags] 
public enum WallLocations 
{ 
    None = 0, 
    Left = 1, 
    Right = 2, 
    Top = 4, 
    Bottom = 8 
} 

Sau đó, bạn có thể sử dụng từ điển để ánh xạ từ vị trí trên tường đến hình ảnh.

Dictionary<WallLocations, Image> map = new Dictionary<WallLocations, Image>(); 

map.Add(WallLocations.None, image0000); 
map.Add(WallLocations.Left, image1000); 
map.Add(WallLocations.Right, image0100); 
map.Add(WallLocations.Top, image0010); 
map.Add(WallLocations.Bottom, image0001); 
map.Add(WallLocations.Left | WallLocations.Right, image1100); 
// .... 

Ít nhất trong C# bạn cũng có thể mở rộng định nghĩa enum với tất cả 16 trường hợp.

[Flags] 
public enum WallLocations 
{ 
    None = 0, 

    Left = 1, 
    Right = 2, 
    Top = 4, 
    Bottom = 8, 

    LeftAndRight = Left | Right, 
    LeftAndTop = Left | Top, 
    LeftAndBottom = Left | Bottom, 
    RightAndTop = Right | Top, 
    RightAndBottom = Left | Bottom, 
    TopAndBottom = Top | Bottom, 

    AllExceptLeft = Right | Top | Bottom, 
    AllExceptRight = Left | Top | Bottom, 
    AllExceptTop = Left | Right | Bottom, 
    AllExceptBottom = Left | Right | Top, 

    All = Left | Right | Top | Bottom 
} 
0

Thay vì làm WALLS_ALL_AROUND một hình ảnh, làm cho nó một đối tượng bao gồm các hình ảnh, và cũng có thể bất kỳ logic khác cần thiết để đối phó với phong trào cho phép và không có điều gì. Trong một đối tượng Location bạn chỉ có thể đặt thuộc tính walls thành số WALLS_ALL_AROUND mà bạn có thể truy vấn hình ảnh và xử lý logic khác liên quan đến tường của bạn.

Vì bạn chỉ cần mười sáu trường hợp của các đối tượng (không thay đổi) này cho mỗi bộ ảnh (mỗi một ảnh có thể là một sublcass singleton Tile nếu bạn chỉ có một bộ ảnh), bạn cũng lưu bộ nhớ.

0

Một giải pháp OO phong nha có thể sẽ liên quan đến Strategy Pattern. Một triển khai có thể là có một lớp WallConfiguration và một WallFactory để tạo chúng. Một Tile sau đó sẽ chứa một WallConfiguration. Triển khai (kiểu C++) sẽ trông giống như sau:

class Tile 
{ 
private: 
    WallConfiguration walls; 
    // Other Tile data 

public: 
    enum Walls 
    { 
     TOP, 
     BOTTOM, 
     LEFT, 
     RIGHT, 
     TOP_RIGHT, 
     TOP_LEFT 
     // Fill in the rest 
    }; //Enums have a place! 
    Tile(Walls wall) 
    { 
     walls = WallFactory.getConfiguration(wall); 
    } 

Một trong những lợi thế thú vị là bây giờ, khi bạn thêm khả năng làm nổ tường (và bạn ... bạn biết bạn ' sẽ tiếp tục, 'vì tất cả chúng ta thích thổi mọi thứ lên), bạn có thể thêm trách nhiệm đó vào lớp WallConfiguration, mà sẽ biết làm thế nào để có được thể hiện thích hợp của chính nó khi bạn thổi lên bức tường bên trái, ví dụ.