2016-03-20 18 views
5

Tôi muốn lập trình một trò chơi và muốn sử dụng mẫu thành phần cho nhiều thực thể.Nim - Tạo chuỗi các đối tượng thực hiện phương thức

Trong ngôn ngữ có giao diện/loại-lớp/đa kế thừa, sẽ không có vấn đề gì.

Tôi muốn một số thực thể có thể cập nhật nhưng không thể hiển thị và một số phải là cả hai.


Haskell:

class Updateable a where 
    update :: Float -> a -> a 

class Renderable a where 
    render :: a -> Picture 

class InputHandler a where 
    handleInput :: Event -> a -> a 

tôi có thể tạo ra một danh sách những thứ mà có thể được cập nhật.

updateAll :: Updateable a => Float -> [a] -> [a] 
updateAll delta objs = map (update delta) objs 

Trong Java/D/... này có thể được thực hiện thông qua giao diện

interface Updateable { 
    void update(float delta); 
} 

// somewhere in a method 
List<Updateable> objs = ...; 
for (Updateable o : objs) { 
    o.update(delta); 
} 

Bây giờ tôi tự hỏi như thế nào điều này có thể được thực hiện trong nim với multimethods.

Liệu sự tồn tại của đa phương thức phù hợp có thể được thể hiện bằng một loại không?

var objs: seq[???] = @[] 



Chỉnh sửa: Thêm nhiều mã và cố định không chính xác Haskell dụ

+0

Có vẻ như [khái niệm] (http://nim-lang.org/docs/manual.html#generics-concepts) là cách để đi, nhưng chúng vẫn là WIP và tôi không thể tạo một 'seq [Cập nhật được] '. 'loại Updateable = khái niệm x cập nhật (x)' – Karroffel

+0

Không rõ chính xác bạn muốn sử dụng đa thừa kế trong ví dụ của bạn như thế nào. Ví dụ, tại sao không đơn giản là không làm gì nếu một thành phần không "implement" render() hoặc update()? Nhìn vào các kiến ​​trúc dựa trên thành phần của các engine phổ biến (Unity3d, UE4), chúng không sử dụng các giao diện cho các lớp cốt lõi mà người dùng thực hiện - dễ nghĩ hơn về kiểu "Thành phần" đơn nhất so với nhiều giao diện có thể cần thực hiện. – endragor

Trả lời

3

Tôi không chắc chắn nếu điều này trả lời câu hỏi của bạn, nhưng nó đáng nhắc đến.

Nếu bạn lưu trữ các đối tượng trò chơi trong các danh sách riêng biệt dựa trên loại, bạn vẫn có thể viết rất nhiều logic chung. Lưu trữ các đối tượng theo loại có hiệu suất tốt hơn tốt hơn vì dự đoán đọc trước và nhánh. Xem bài giảng này, từ một anh chàng nên biết những gì anh ta nói về: Multiprocessor Game Loops: Lessons from Uncharted 2: Among Thieves.

Ví dụ: nếu bạn đã xác định được texture proc cho một số loại đối tượng của mình, thì bạn có thể viết một số chung chung là draw(t: T) = magicRenderToScreen(texture(t)) proc sẽ hoạt động cho tất cả chúng. Điều này cũng hữu ích nếu bạn đang triển khai các nhóm tài nguyên hoặc bất kỳ loại hành vi chung nào thực sự.

Bạn phải bao gồm từng loại đối tượng bị ảnh hưởng trong các vòng kết xuất và cập nhật bằng cách nào đó, nhưng đó thường không phải là vấn đề lớn trong thực tế.Bạn thậm chí có thể sử dụng macro đơn giản để làm cho chi tiết này ít tiết hơn, do đó vòng lặp kết xuất của bạn chỉ chứa một số thứ như renderAll(players, enemies, sprites, tiles)

Danh sách chung không đơn giản trong ngôn ngữ được biên dịch, và bắt buộc bạn thấy nó, rất tốt khi bạn đang làm việc trên một trò chơi. Để có danh sách chung bạn thường phải sử dụng con trỏ và công văn động, hoặc một số loại hình công đoàn. Tôi dường như nhớ rằng nim được sử dụng để có thể gửi đến nhiều phương thức chính xác từ ref của đối tượng cha mẹ, (điều này sẽ cho phép các danh sách chứa một số kiểu và gửi động vào thời gian chạy), nhưng tôi thành thật không chắc liệu nó có còn làm xong...?

Ai đó có kiến ​​thức hơn, vui lòng cho chúng tôi biết!

+0

Cảm ơn câu trả lời. Các công văn năng động dựa trên một siêu lớp phổ biến vẫn có thể được thực hiện, nhưng tôi đã cố gắng để mô phỏng đa thừa kế thông qua giao diện (mà không tồn tại). Tôi sẽ đi với nhiều danh sách các loại khác nhau. – Karroffel

+0

Suy nghĩ về nó nhiều hơn, tôi đoán nó có thể có danh sách các hành vi quá, và sau đó soạn các đối tượng trò chơi ngoài tham chiếu đến các danh sách đó. – Jostein

3

Việc thiếu một interface từ khóa rõ ràng là common question in the Nim community. Lấy câu trả lời Araq và áp dụng nó vào một tình huống giả định dựa trên đoạn Java/D bạn, chúng tôi có thể viết một cái gì đó như thế này:

import strutils # For formatFloat 

type 
    IUpdateable = 
    tuple[ 
     update: proc(v: float) {.closure.}, 
     show: proc(): string {.closure.} 
     ] 

    Rounded = ref object 
    internalValue: float 

    Real = ref object 
    a_real_value: float 

# Here goes our rounded type. 
proc `$`(x: Rounded): string = 
    result = "Rounded{" & $int(x.internalValue) & "}" 

proc updateRounded(x: Rounded, delta: float) = 
    x.internalValue += delta 

proc getUpdateable(x: Rounded): IUpdateable = 
    result = (
    update: proc(v: float) = x.updateRounded(v), 
    show: proc(): string = `$`(x) 
    ) 

converter toIUpdateable(x: Rounded): IUpdateable = 
    result = x.getUpdateable 

# Here goes our Real type. 
proc `$`(x: Real): string = 
    result = "Real{" & 
    x.a_real_value.format_float(precision = 3) & "}" 

proc update_real(x: Real, delta: float) = 
    x.a_real_value += delta 

proc getUpdateable(x: Real): IUpdateable = 
    result = (
    update: proc(v: float) = x.update_real(v), 
    show: proc(): string = `$`(x) 
    ) 

# Here goes the usage 
proc main() = 
    var objs: seq[IUpdateable] = @[] 
    var a = Rounded() 
    var b = Real() 
    a.internalValue = 3.5 
    b.a_real_value = 3.5 

    objs.add(a) # works because of toIUpdateable() 
    objs.add(b.getUpdateable) 

    for obj in objs: 
    echo "Going through one loop iteration" 
    echo "\t", obj.show() 
    obj.update(0.4) 
    echo "\t", obj.show() 
    obj.update(0.4) 
    echo "\t", obj.show() 

main() 
# -> Going through one loop iteration 
# -> Rounded{3} 
# -> Rounded{3} 
# -> Rounded{4} 
# -> Going through one loop iteration 
# -> Real{3.50} 
# -> Real{3.90} 
# -> Real{4.30} 

Tuy nhiên, như bạn có thể read in that forum thread, tùy thuộc vào chính xác những gì bạn cần giao diện cho cách tiếp cận khác có thể tốt hơn. Ngoài ra, có lẽ cách tương lai để đi là concepts, nhưng như thường lệ hướng dẫn sử dụng là khô và the related unit tests are cryptic vì vậy tôi không thể quản lý để dịch ví dụ tuple trước đó thành các khái niệm.

Nếu bạn muốn đi cho các khái niệm bạn nên hỏi trực tiếp trên diễn đàn, nhưng hãy cẩn thận, như hướng dẫn sử dụng, concepts are still in development.

+0

Có vẻ như cách tiếp cận khái niệm là một kết thúc chết. Các khái niệm không có biểu diễn thời gian chạy. Người ta không bao giờ có thể tạo một 'seq [Updateable]'. Sử dụng một tuple đóng cửa không cảm thấy đúng. Nó giống như xây dựng vtable của riêng bạn bởi vì trình biên dịch không thể. Tôi hy vọng Nim được giao diện trước khi phát hành 1.0 – Karroffel

+1

Nói chung ý tưởng với Nim là nó [lá bạn khả năng để thực hiện các tính năng như vậy] (https://bitbucket.org/fowlsoft/interfaces/wiki/Home), giống như ở đó không có macro OOP chính thức, [nhưng bạn có thể tạo macro của riêng mình] (http://nim-by-example.github.io/oop_macro/). –

Các vấn đề liên quan