2017-03-18 1 views
0

자바를 배우려면 고전적인 "우주에서 날아 다니는"2D 게임을 만들고 있습니다. 플레이어 오브젝트 외에도 GameObject 클래스를 확장하는 고유 한 클래스가있는 수많은 적/장애물 (스 캐빈 저, 사냥꾼, 혜성, 소행성)이 있습니다. 여러 scavengers, 혜성 등이있을 수 있기 때문에 이들은 arraylists에 저장됩니다. 그러나 각 객체가 상호 작용할 수 있기 때문에 혜성 arraylist, 소행성 배열리스트 등의 객체에 따라 각각의 외계인이 상호 작용할 수 있도록 많은 반복 및 코드가 있습니다. 내 게임 업데이트 기능에서게임 디자인 : 오브젝트 arraylists 구성

내가 가진 :

public void update() { 

    ArrayList<Rock> rockList = rock.getRockList(); 
    ArrayList<Scavenger> scavengerList = scavenger.getScavengerList(); 
    ArrayList<Hunter> hunterList = hunter.getHunterList(); 
    .... 
    npc.update(player, scavengerList, hunterList, rockList); 
    ... 

가}

public void update(Player player, ArrayList<Scavenger> scavengerList, ArrayList<Hunter> hunterList, ArrayList<Rock> rockList) { 

    for(int i = 0; i < scavengerList.size(); i++) {   
     scavengerList.get(i).update(player,scavengerList, ,hunterList rockList); 
    } 
    for(int i = 0; i < hunterList.size(); i++) {    
     hunterList.get(i).update(player,scavengerList, hunterList, rockList); 
    } 
... 
} 

그리고 (게임 오브젝트 클래스를 확장)

내 NPC 클래스의

마침내 나는 업데이트 기능이 내 청소부 수업, 사냥꾼 수업 등

public class Hunter extends NPC{ 
... 
public void update(Player player,ArrayList<Scavenger> scavengerList, ArrayList<Hunter> hunterList, ArrayList<Rock> rockList) { 
"update all hunter objects according to the player, scavengers, rocks etc" 
} 

이 접근법은 다소 번거롭고 더 많은 클래스가 만들어지면 숫자 또는 arraylists를 파싱하고 반복해야 할 필요가 없습니다. 누구든지이 작업을 더 효과적으로 수행 할 것을 권장 할 수 있습니까? 모든 NPC 개체를 포함하는 목록 하나를 가지고 클래스 형식을 추적하고 이에 따라 업데이트하는 것이 확실한 방법 일 것입니다. 더 좋은 방법인가요? 아니면 누군가가 올바른 방향으로 나를 가리킬 수 있습니까?

+0

'World' 인스턴스를 전달하는 것이 더 쉽지 않을까요? 당신은 기본적으로 for (updatableThing : updatableThings) {updatableThing.update (world); }' – plalx

+0

어쩌면 완전히 이해하지 못했지만 (여전히 배우기는하지만) World 인스턴스는 모든 개체를 포함하고 업데이트하는 목록을 보유하고 있거나 잘못 이해하고 있습니까? – user2913053

답변

2

예 훨씬 더 좋은 방법이 있습니다.

게임의 각 유형에 대해 전시 할 행동/특성 집합을 연구하십시오. 이러한 동작은 인터페이스로 정의해야합니다. 그런 다음 행동/특성을 다루는 코드는 실제 클래스에 대해 전혀 알지 못해도 인터페이스를 사용할 수 있습니다.

public interface Moving { 
    void move(); 
    boolean hasCollided(Shape shape); 
    void handleCollision(Collision collision); 
} 

다음이 인터페이스를 구현하는 것이 이동하는 모든 클래스 : 일부 개체가 자신의 현재 속도에 따라 각 회전을 이동 가능성이 다른 물체와 충돌 할 수있는 경우

예를 들어, 다음의 인터페이스가있을 수 있습니다. 거기에

movingObjects.forEach(Moving::move); 

update 방법의 다음 World 객체는 다음 List<Moving> movingObjects 및 사용 가질 수있다.

: 인터페이스를 구현하는 여러 클래스가 다음 별도의 클래스로 그 논리를 이동해야 자신을 이동하는 유사한 메커니즘을 사용하는 경우

List<Collision> collisions = getAllCollisions(movingObjects); 
for (Collision collision: collisions) { 
    for (Moving element: collision.getCollidingObjects) { 
     element.handleCollision(collision); 
    } 
} 

:

당신이 뭔가를 할 수도 있습니다 이동 한 후 충돌을 처리하려면

class Inertia implements Moving { 
    private Velocity velocity; 

    @Override 
    public void move(Shape shape) { 
     velocity.applyTo(shape); 
    } 

    @Override 
    public void applyForceFrom(Position position) { 
     velocity.accelerateAwayFrom(position); 
    } 
} 

다음이 클래스에 자신의 이동 동작을 위임 할 수 있습니다 귀하의 세계 객체 :

class Asteroid implements Moving { 
    private final Inertia inertia; 
    private Shape shape = new Circle(radius); 

    @Override 
    public void move() { 
     inertia.move(shape); 
    } 

    @Override 
    public boolean hasCollided(Shape other) { 
     return this.shape.intersects(other); 
    } 

    @Override 
    public void handleCollision(Collision collision) { 
     intertia.applyForceFrom(collision.getCentreOfMass()); 
    } 
} 

이것은 불필요한 간접적 인 것처럼 보일 수 있지만 경험상 볼 때 장기적으로 보람 있습니다. 자세한 내용은 Delegation Pattern을 참조하십시오.

개체마다 동작이 다른 경우 (예 : 중력에 영향을받는 일부, AI 등으로 제어되는 일부), 또는 클래스가 move (예 : 중력 및 관성) 또는 클래스에 하나 이상의 대리자를 적용 할 수있는 경우 여러 대리인이있을 수 있습니다. 행동이 고유하면 move을 구현할 수 있습니다. 이 모든 일은 World 개체의 클래스에 대해 전혀 알 필요가 없으면 move을 호출하는 것입니다.

일반적으로 수퍼 클래스에서 동작을 상속하기 위해 extends을 사용하지 마십시오. GameObject를 확장하는 NPC 확장 NPC의 구조는 Hunter가 적 또는 AIC 제어 또는 다른 것을 확장하기를 원할 때까지 편리합니다. 어려운 경험은 OO 코더에게 이러한 유형의 계층 구조가 처음에는 합리적이고 우아한 것처럼 보이지만 더 복잡한 기능을 추가 할 때 관리하기 어려워집니다.

어떤 개체가 어떤 동작 인터페이스를 구현하는지 세부 정보를 숨기려면 World에서 Visitor Pattern을보고 싶을 것입니다. 이렇게하면 월드 오브제는 모든 게임 객체를 발동기로 방문한 다음 AIAgent로 방문한 다음 방문객이 무엇을하는지 전혀 알지 못해도 사용자가 제어하는 ​​객체로 방문 할 수 있습니다. 그것은 잘 적용되면 매우 강력하지만 익숙해지기까지는 약간의 시간이 걸립니다.

마지막으로 게임 작성자가 사용하는 매우 일반적인 아키텍처 패턴이 Entity Component System입니다. 만약 당신이 자바를 배우는 중이라면 지금 당장은 이것을 무시 하겠지만, 당신이 진지한 게임 개발자가된다면 위에서 설명한 아키텍처보다 개선 된 것 같을 것입니다.

나는 분명 예 세부 많이 남겨 두었다 그러나 그것은 일반적인 생각 (예 : Shape, Circle, Position, Velocity, Collision 등의 정의 등). 이것에 더 많은 것이 있습니다. 객체 지향 디자인에 대한 책이나 튜토리얼을 살펴 보는 것이 좋습니다.

+0

매우 철저한 대답에 감사드립니다. 비슷한 클래스에서 코드를 반복하는 것을 피할 수있는 방법을 알 수 있습니다. 그러나 물체의 움직임이 서로에 달려 있다면 어떨까요? 바위가 충돌하여 방향을 바꿀 수 있으며, 사냥꾼은 바위를 피하거나 플레이어를 추적 할 수 있습니다. 그것은 이동 함수가 모든 객체를 알고 그에 따라 움직임을 계산할 것을 요구합니다. move 함수가 어떤 오브젝트를 호출했는지 알았고 원래 목록에서 언급했듯이 기본적으로 현재 목록이 하나로 합쳐진 이동 목록을 반복합니다. – user2913053

+0

필자는이 답변을 처리하는 방법을 알려주기 위해 충돌에 대한 일반적인 모델을 제공합니다. 비슷한 모델이 당신의 다른 예제에서도 잘 작동 할 것입니다. – sprinter

+0

내 대답은 지금 엄청나게 길어지고있다. 도움이 되었다면 받아 들여서 도움이 필요한 구체적인 것이 있는지 다른 질문을하십시오. – sprinter