New Path based on time intervals; see levels/test/platform.stl
authorChristoph Sommer <mail@christoph-sommer.de>
Tue, 21 Mar 2006 21:04:24 +0000 (21:04 +0000)
committerChristoph Sommer <mail@christoph-sommer.de>
Tue, 21 Mar 2006 21:04:24 +0000 (21:04 +0000)
SVN-Revision: 3110

data/levels/test/platform.stl
src/object/path.cpp
src/object/path.hpp
src/object/platform.cpp

index 62594af..d6fb14a 100644 (file)
          (image "images/background/arctis.jpg")
          (speed 0.500000)
        )
-   (path (name "path1") (circular #t) (speed 100) (x 0) (y 0) (x 0) (y -100) (x 100) (y -100) (x 100) (y 0))
-   (path (name "path2") (circular #t) (speed 100) (x 0) (y 0) (x 0) (y 100) (x 100) (y 100) (x 100) (y 0))
+
+   (path 
+     (name "path1") 
+     (circular #t) 
+     (nodes 
+       (node (x 0)   (y 0)) 
+       (node (x 0)   (y 0)) 
+       (node (x 0)   (y -100)) 
+       (node (x -100)(y -100)) 
+       )
+     )
+   (path 
+     (name "path2") 
+     (circular #t) 
+     (nodes 
+       (node (x 0)   (y 0)    (time 1)) 
+       (node (x 0)   (y 0)    (time 1)) 
+       (node (x 0)   (y -100) (time 1)) 
+       (node (x 0)   (y -100) (time 1)) 
+       )
+     )
+   (path 
+     (name "path3") 
+     (circular #t) 
+     (nodes 
+       (node (x 0)   (y 0)    (time 1)) 
+       (node (x 0)   (y 0)    (time 1)) 
+       (node (x 0)   (y -100) (time 2)) 
+       )
+     )
+   (path 
+     (name "path4") 
+     (circular #t) 
+     (nodes 
+       (node (x 0)   (y 0)    (time 1)) 
+       (node (x 0)   (y -100) (time 1)) 
+       (node (x 0)   (y -200) (time 1)) 
+       (node (x 0)   (y -100) (time 1)) 
+       )
+     )
+   (path 
+     (name "path5") 
+     (circular #f) 
+     (nodes 
+       (node)
+       (node (y -100))
+       (node (x 100))
+       (node (y 0))
+       (node (x 0))
+       )
+     )
+
    (platform (use_path "path1") (x 200) (y 850) (type "block1"))
-   (platform (use_path "path1") (x 232) (y 850) (type "block2"))   
-   (platform (use_path "path2") (x 264) (y 650) (type "block2"))
-   (platform (use_path "path2") (x 296) (y 650) (type "block2"))
-   (platform (use_path "path1") (x 328) (y 850) (type "block2"))
-   (platform (use_path "path1") (x 360) (y 850) (type "block2"))
-   (platform (use_path "path2") (x 392) (y 650) (type "block2"))
-   (platform (use_path "path2") (x 424) (y 650) (type "block2"))
-   (platform (use_path "path1") (x 456) (y 850) (type "block2"))
-   (platform (use_path "path1") (x 488) (y 850) (type "block3"))
+   (platform (use_path "path1") (x 232) (y 850) (type "block3"))   
+   (platform (use_path "path2") (x 264) (y 850) (type "block1"))
+   (platform (use_path "path2") (x 296) (y 850) (type "block3"))
+   (platform (use_path "path3") (x 328) (y 850) (type "block1"))
+   (platform (use_path "path3") (x 360) (y 850) (type "block3"))
+   (platform (use_path "path4") (x 392) (y 850) (type "block1"))
+   (platform (use_path "path4") (x 424) (y 850) (type "block3"))
+   (platform (use_path "path5") (x 456) (y 850) (type "block1"))
+   (platform (use_path "path5") (x 488) (y 850) (type "block3"))
    (powerup (x 100) (y 700) (sprite "images/powerups/egg/egg.sprite"))
    (jumpy (x 140) (y 750))
    (spawnpoint (name "main") (x 340) (y 800))
index 251afd0..bf7fefc 100644 (file)
@@ -1,7 +1,8 @@
 //  $Id$
 // 
-//  SuperTux
+//  SuperTux Path
 //  Copyright (C) 2005 Philipp <balinor@pnxs.de>
+//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
 //
 //  This program is free software; you can redistribute it and/or
 //  modify it under the terms of the GNU General Public License
 #include "object_factory.hpp"
 
 #include <assert.h>
+#include <iostream>
+#include <stdexcept>
 
-
-// some constants
-#define DEFAULT_PIXELS_PER_SECOND      50
-#define EPSILON                                1.5
+// snap to destination if within EPSILON pixels
+#define EPSILON 1.5
 
 Path::Path(const lisp::Lisp& reader)
 {
+  circular = true;
   forward = true;
-  float x = 0, y = 0;
 
-  lisp::ListIterator iter(&reader);
+  if (!reader.get("name", name)) throw std::runtime_error("Path without name");
+  reader.get("circular", circular);
+  reader.get("forward", forward);
 
-  assert (iter.next());
-  std::string token = iter.item();
-  assert(token == "name");
-  iter.value()->get(name);
+  const lisp::Lisp* nodes_lisp = reader.get_lisp("nodes");
+  if(!nodes_lisp) throw std::runtime_error("Path without nodes");
 
-  circular = true;
-  assert (iter.next());
-  token = iter.item();
-  if (token == "circular") {
-    iter.value()->get(circular);
-    iter.next();
-  }
+  lisp::ListIterator iter(nodes_lisp);
 
-  pixels_per_second = DEFAULT_PIXELS_PER_SECOND;
-  assert (iter.next());
-  token = iter.item();
-  if (token == "speed") {
-    iter.value()->get(pixels_per_second);
-    iter.next();
-  }
-  do {
-    token = iter.item();
-    if(token == "x") {
-      iter.value()->get(x);
-    } else if(token == "y") {
-      iter.value()->get(y);
-      points.push_back(Vector(x,y));
+  PathNode node;
+  node.time = 1;
+
+  while(iter.next()) {
+    if(iter.item() != "node") {
+      std::cerr << "Warning: unknown token '" << iter.item() << "' in Path nodes list. Ignored." << std::endl;
+      continue;
     }
-  } while(iter.next());
+    const lisp::Lisp* node_lisp = iter.lisp();
+
+    // each new node will inherit all values from the last one
+    node_lisp->get("x", node.position.x);
+    node_lisp->get("y", node.position.y);
+    node_lisp->get("time", node.time);
+
+    if(node.time <= 0) throw std::runtime_error("Path node with non-positive time");
 
-  next_target = points.begin();
-  pos = *next_target;
+    pathNodes.push_back(node);
+  }
+
+  if (pathNodes.size() < 1) throw std::runtime_error("Path with zero nodes");
 
-  calc_next_velocity();
+  // initial position and velocity will be set with the first update, as timeToGo is initialized to 0.
+  destinationNode = 0;
 
   // register this path for lookup:
   registry[name] = this;
@@ -82,31 +80,62 @@ Path::~Path()
   registry.erase(name);
 }
 
-void
+       void
 Path::update(float elapsed_time)
 {
+
+  // advance to next node at scheduled time
+  if (timeToGo <= 0) {
+    position = pathNodes[destinationNode].position;
+
+    // set destinationNode to next node
+    if (forward) {
+      destinationNode++;
+      if (destinationNode >= (int)pathNodes.size()) {
+       if (circular) {
+         destinationNode = 0;
+       } else {
+         destinationNode = (int)pathNodes.size()-1;
+       }
+      }
+    } else {
+      destinationNode--;
+      if (destinationNode < 0) {
+       if (circular) {
+         destinationNode = (int)pathNodes.size()-1;
+       } else {
+         destinationNode = 0;
+       }
+      }
+    }
+
+    PathNode dn = pathNodes[destinationNode];
+    timeToGo = dn.time;
+    velocity = (dn.position - position) / timeToGo;
+  }
+
+  // move according to stored velocity
   last_movement = velocity * elapsed_time;
-  pos += last_movement;
-  if ((pos - *next_target).norm() < EPSILON) {
-    pos = *next_target;
-    calc_next_velocity();
+  position += last_movement;
+  timeToGo -= elapsed_time;
+
+  // stop when we arrive at our destination
+  PathNode dn = pathNodes[destinationNode];
+  if ((position - dn.position).norm() < EPSILON) {
+    velocity = Vector(0,0);
   }
+
 }
 
 void
 Path::draw(DrawingContext& )
 {
-   // TODO: Add a visible flag, draw the path if true
+  // TODO: Add a visible flag, draw the path if true
 }
 
 const Vector&
 Path::GetPosition() {
-  return pos;
-}
-
-const Vector&
-Path::GetStart() {
-  return *(points.begin());
+  return position;
 }
 
 const Vector&
@@ -114,36 +143,11 @@ Path::GetLastMovement() {
   return last_movement;
 }
 
-void
-Path::calc_next_velocity()
-{
-  Vector distance;
-
-  if (circular) {
-    ++next_target;
-    if (next_target == points.end()) {
-      next_target = points.begin();
-    }
-  }
-  else if (forward) {
-    ++next_target;
-    if (next_target == points.end()) {
-      forward = false;
-    }
-  }
-  else {
-    //FIXME: Implement going backwards on the list
-    //       I have no f***ing idea how this is done in C++
-  }
-
-  distance = *next_target - pos;
-  velocity = distance.unit() * pixels_per_second;
-}
 
 //////////////////////////////////////////////////////////////////////////////
 // static stuff
 
-PathRegistry Path::registry;
+std::map<std::string,Path*> Path::registry;
 
 Path*
 Path::GetByName(const std::string& name) {
index 97f21ab..452e942 100644 (file)
@@ -1,7 +1,8 @@
 //  $Id$
 // 
-//  SuperTux
+//  SuperTux Path
 //  Copyright (C) 2005 Philipp <balinor@pnxs.de>
+//  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
 //
 //  This program is free software; you can redistribute it and/or
 //  modify it under the terms of the GNU General Public License
 #include "lisp/lisp.hpp"
 
 
-class   Path;
-typedef std::map<std::string,Path*>       PathRegistry;
-
-
-typedef std::list<Vector>                 PathPoints;
-typedef std::list<Vector>::const_iterator PathPointIter;
+/**
+ * Helper class that stores an individual node of a Path
+ */
+class PathNode
+{
+public:
+  Vector position; /**< position (in pixels) of this node */
+  float time; /**< time (in seconds) to get to this node */
+};
 
 
+/**
+ * Path an object can travel along. Made up of multiple nodes of type PathNode.
+ */
 class Path : public GameObject
 {
 public:
@@ -47,27 +54,25 @@ public:
   virtual void draw(DrawingContext& context);
 
   const Vector& GetPosition();
-  const Vector& GetStart();
   const Vector& GetLastMovement();
 
   // WARNING: returns NULL if not found !
   static Path* GetByName(const std::string& name);
 
 private:
-  std::string       name;
-  float             pixels_per_second;
-  PathPoints        points;    
-  PathPointIter     next_target;
-  Vector            pos;
-  Vector            velocity;
-  Vector            last_movement;
+  std::string name; /**< name this path can be referenced with, stored in PathRegistry */
+  bool circular; /**< true: start with the first node once the last one has been reached. false: path will stop at last node */
+  bool forward; /**< true: travel to nodes in the order they were defined. false: inverse order */
+  std::vector<PathNode> pathNodes; /**< list of nodes that make up this path */
 
-  bool              circular;
-  bool              forward;
+  Vector position; /**< current position */
+  Vector velocity; /**< current velocity */
+  Vector last_movement; /**< amount of pixels we moved in the last call to update */
 
-  void calc_next_velocity();
+  int destinationNode; /**< current destination Node */
+  float timeToGo; /**< seconds until we arrive at the destination */
 
-  static PathRegistry registry;
+  static std::map<std::string,Path*> registry;
 };
 
 #endif
index 374a4ee..8d1a8f3 100644 (file)
@@ -49,7 +49,7 @@ Platform::Platform(const lisp::Lisp& reader)
      std::cerr << "Warning: Path for moving platform not found! Make sure that the name is spelled correctly,\nand that the path is initialized before the platform in the level file!\n";
   }
 
-  path_offset = bbox.p1 - path->GetStart();
+  path_offset = bbox.p1;
 }
 
 Platform::~Platform()