Author Topic: Run and hide  (Read 34642 times)

Etinarg

  • Rogueliker
  • ***
  • Posts: 424
  • Karma: +1/-1
  • Idea archivist and game tinkerer.
    • View Profile
    • Gedankenweber Blog (German)
Re: Run and hide
« Reply #15 on: December 10, 2009, 08:58:43 AM »
I'm going to have to do something else though when I start looking at pathfinding for individual creatures looking to move to other random points on the map. If I'm doing a breadth-first search for each and every one of those instances, then I think it's going to slow it all down. Anyway, that's tomorrow's problem.

Breadth-first search is slow in wide open areas. In places of small rooms and corridors it works quite well. So I'd not expect any problems.

You usually don't need to do pathfinding for many beings in a turn, those who have a path already can follow it until they hit an obstacle ... or unless the target moves. So if a creature is thirsty, and the well is always in the same spot, it can call the pathfinder once, and move along the found path in the subsequent turns until it hits a obstacle, and then tries to find a better path.

A* often performs better, but it's a whole lot more complicated to implement.

Slash uses Eclipse, he told in another thread, so he might be able to help there.

purestrain

  • Rogueliker
  • ***
  • Posts: 172
  • Karma: +0/-0
    • View Profile
Re: Run and hide
« Reply #16 on: December 10, 2009, 12:06:26 PM »
I would even suggests to create a higher level representation of the map. There is »usually« no need to do tile-by-tile pathfinding, just from area to area.

And hell, i always write zombie roguelikes because they don't need any form of intelligence...  :P

Etinarg

  • Rogueliker
  • ***
  • Posts: 424
  • Karma: +1/-1
  • Idea archivist and game tinkerer.
    • View Profile
    • Gedankenweber Blog (German)
Re: Run and hide
« Reply #17 on: December 10, 2009, 03:03:27 PM »
Maybe some day someone writes "dungeon chess", with two groups of creatures battling turn by turn on a roguelike map?

pat

  • Rogueliker
  • ***
  • Posts: 193
  • Karma: +0/-0
    • View Profile
Re: Run and hide
« Reply #18 on: December 11, 2009, 01:03:33 AM »
And hell, i always write zombie roguelikes because they don't need any form of intelligence...  :P
haha, yep, that's how this started. But I'm trying to put in some kind of POWER ZOMBIE who can sense where you are but moves slowly so you can't just sit and hide forever. And that's where the pathfinding comes in.

pat

  • Rogueliker
  • ***
  • Posts: 193
  • Karma: +0/-0
    • View Profile
Re: Run and hide
« Reply #19 on: December 30, 2009, 04:28:16 AM »
In between bouts of playing too much dungeon crawl stone soup (a game which I previously thought was lacklustre and is now taking over my free time) I've included one heck of a goofy pathfinder and some heat-seeking revenants to mix up the gameplay.

Does anyone have a good example of a breadth-first java pathfinding example so I can compare it to my own? I'm somewhat embarrassed by the dirty coding I've done and wouldn't mind seeing an example of something which resembles 'best standard'  ::) :-\

Etinarg

  • Rogueliker
  • ***
  • Posts: 424
  • Karma: +1/-1
  • Idea archivist and game tinkerer.
    • View Profile
    • Gedankenweber Blog (German)
Re: Run and hide
« Reply #20 on: December 30, 2009, 11:12:56 AM »
I once wrote this. It should work fairly well, but it is a primitive breadth-first search, so it will examine more squares than e.g. a good A* will do. It was good enough for my purpose though.

The "step" functions are used to make something follow the path. findPath() does the actual pathfinding.

You'll need a replacement for my Map class that defines the needed methods ... this code won't compile all by itself. Particularly you must implement the map.isMoveAllowed() method which checks if a move from one square to another is allowed; this is too project specific to be coded in a generic fashion

Code: [Select]
/*
 * Path.java
 *
 * Created on 9. December 2008
 *
 * Copyright (c) Hansjoerg Malthaner
 * hansjoerg.malthaner@gmx.de
 *
 * This file is available under the GPL v2 or newer.
 * http://www.gnu.org/licenses/gpl-2.0.html
 */

import java.util.ArrayList;
import java.util.Stack;

/**
 * A path of discrete steps from one location to another.
 * This pathfinding implementation is not reentrant, so each thread
 * needs it's own instance of a path for pathfinding.
 *
 * @author Hj. Malthaner
 */
public class Path {
    
    /**
     * One step of the path. The path as a whole is a linked list of these nodes.
     * @author Hj. Malthaner
     */
    public class Node {
        public int x, y;
        Node link;
        
        Node(int x, int y) {
            this.x = x;
            this.y = y;
        }

        Node(int x, int y, Node link) {
            this.x = x;
            this.y = y;
            this.link = link;
        }

    }
    
    /** Result path of pathfinding */
    private ArrayList path;

    /** Current step in stepping through the path */
    private int step;

    /** Marks used in pathfinding. */
    private boolean [] marks;
    
    /** Look ahead on next step */
    public Node nextStep()
    {
        return getStep(step+1);
    }
    
    /** Retrieve current step */
    public Node currentStep()
    {
        return getStep(step);
    }

    /** Random access for a step */
    public Node getStep(int n)
    {
        if(n >= 0 && n < path.size()) {
            return (Node)path.get(n);
        }
        return null;
    }
    
    /** Advance current step by one. */
    public void advance()
    {
        step ++;
    }
    
    /** Add a step to this path */
    public void addStep(int x, int y)
    {
        path.add(new Node(x, y));
    }
    
    /** Reset path, remove all nodes.*/
    public void clear()
    {
        path = new ArrayList();
        step = 0;
    }
    
    /**
     * Breadth first pathfinding.
     *
     * @param map the map to search
     * @param sx Source x-coordinate
     * @param sy Source y-coordinate
     * @param dx Destination x-coordinate
     * @param dy Destination y-coordinate
     *
     * @return true if path was found, false otherwise
     *
     * @author Hj. Malthaner
     */
    public boolean findPath(Map map, int sx, int sy, int dx, int dy)
    {
        clear();

        marks = new boolean[map.getWidth()*map.getHeight()];
        ArrayList queue = new ArrayList();

        queue.add(new Node(sx, sy));
        marks[sy*map.getWidth() + sx] = true;

        Node p;

        do {
            p = (Node)queue.remove(0);
            
            
            if(p.x == dx && p.y == dy) {
                // Hajo: destination found
                // unwind path
                
                Stack stack = new Stack();
                
                while(p.link != null) {
                    stack.push(p);
                    p = p.link;
                }

                // Hajo: Push starting node
                stack.push(p);
                
                // Hajo: Setup path
                while(stack.isEmpty() == false) {
                    p = (Node)stack.pop();
                    addStep(p.x, p.y);
                    // System.err.println("x=" + p.x + " y=" + p.y);
                }
                
                return true;
            } else {
                checkMove(map, queue, p, 1, 0);
                checkMove(map, queue, p, 0, 1);
                checkMove(map, queue, p, -1, 0);
                checkMove(map, queue, p, 0, -1);
            }
         } while(queue.isEmpty() == false);

        return false;
    }

    /** Recursive pathfinding in the 4 cardinal directions. */
    private void checkMove(Map map, ArrayList queue, Node p, int w, int h)
    {
        final int dx = p.x+w;
        final int dy = p.y+h;
        
        if(map.isMoveAllowed(p.x, p.y, dx, dy) &&
           marks[dy*map.getWidth() + dx] == false)
        {
            queue.add(new Node(dx, dy, p));
            marks[dy*map.getWidth() + dx] = true;
        }
    }
    
    /** Creates a new instance of Path */
    public Path()
    {
        clear();
    }  
}

Edit: Fixed some typos.
Edit 2: Added more comments.
« Last Edit: December 30, 2009, 04:34:02 PM by Hajo »

pat

  • Rogueliker
  • ***
  • Posts: 193
  • Karma: +0/-0
    • View Profile
Re: Run and hide
« Reply #21 on: December 30, 2009, 10:58:36 PM »
thanks! I'll compare that to mine and see what I did wrong, heh (nervous laugh)


Etinarg

  • Rogueliker
  • ***
  • Posts: 424
  • Karma: +1/-1
  • Idea archivist and game tinkerer.
    • View Profile
    • Gedankenweber Blog (German)
Re: Run and hide
« Reply #22 on: December 31, 2009, 10:58:09 AM »
Good luck with that :)

I made a minimal map class which allows to compile the pathfinding example, and illustrates the needed methods:

Code: [Select]
/*
 * Map.java
 *
 * Created on 31. December 2009
 *
 * Copyright (c) Hansjoerg Malthaner
 * hansjoerg.malthaner@gmx.de
 *
 * This file is available under the GPL v2 or newer.
 * http://www.gnu.org/licenses/gpl-2.0.html
 */
 
 /**
  * Minimal map class to compile the pathfinding example.
  * @author Hj. Malthaner
  */
 public class Map
 {
/** Map width */
private int width;

/** Map height */
private int height;

/** @return map width */
public int getWidth()
{
return width;
}

/** @return map height */
public int getHeight()
{
return height;
}

/**
* Checks if a move is allowed
* @return true if move is allowed, false otherwise
*/
public boolean isMoveAllowed(int fromX, int fromY,
                            int toX, int toY)
{
return true;
}

/** Constructs a new map of width x height */
public Map(int width, int height)
{
this.width = width;
this.height = height;
}
}

You will want to write a better implementation of isMoveAllowed() using your games real map data and movement constraints.
« Last Edit: December 31, 2009, 12:08:09 PM by Hajo »