Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411587 Posts in 69386 Topics- by 58443 Members - Latest Member: Mansreign

May 06, 2024, 09:07:00 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Smooth movement for NPCs in a shmup?
Pages: [1]
Print
Author Topic: Smooth movement for NPCs in a shmup?  (Read 3271 times)
Akhel
Level 10
*****



View Profile
« on: May 31, 2009, 09:16:14 AM »

I may or may not be making a shmup in C++ and Allegro, and in case I am I'm having some trouble with the way NPCs move. What I have in place right now is an Actor class (which is the parent of Bullet, Enemy and Player) which has three variables - dirx, diry and speed. dirx and diry are the dimensions of a vector, and I multiply them by speed to move the Actor.

Thing is, right now the enemies' movement isn't fluid enough. The only way I know to change their movement direction smoothly is to increment or decrement the dirx and diry variables until they're around the value I want them to be, which is a very troublesome method for more complex movement patterns.

A quick Google search returned some information on splines, which I suppose would be the best solution, but I couldn't find any good tutorials on the subject and the Allegro example is pretty much illegible to me.

Is this indeed the best way to go (also considering I'm not an experienced programmer)? If so, where can I find some more detailed information on the code and maths? Otherwise, what should I be looking for?

Thanks.
Logged
Ivan
Owl Country
Level 10
*


alright, let's see what we can see


View Profile
« Reply #1 on: May 31, 2009, 08:44:54 PM »

I've never made a shmup but bezier paths seem like a decent idea.

Here's a pretty good tutorial on bezier curves and surfaces:
http://www.gamedev.net/reference/articles/article1808.asp

The easier way to go would be just to use sine waves and such, but you'll be limited to only so much movement types.

I'd say maybe start with some simple sine waves and then if you're feeling frisky, get some bezier paths in.
Logged

http://polycode.org/ - Free, cross-platform, open-source engine.
Wilson Saunders
Level 5
*****


Nobody suspects the hamster


View Profile WWW
« Reply #2 on: June 01, 2009, 11:18:51 AM »

I think you are looking for how to apply the spline algorithem to your code to, so here is my advice:


Step 1: make an enemy class
Code:
class Enemy{
public:
   double locationX;
   double locationY;

   double startX;
   double startY;
   double ctrl1X;
   double ctrl1Y;
   double ctrl2X;
   double ctrl2Y;
   double endX;
   double endY;
   double frac;
   double speed;
public:
   Enemy();
   ~Enemy();

   double CalcSpline (double start, double ctrl1, double ctrl2, double end, double frac);
   void Update();

}


Step 2: impliment the spline calculation function like so
Code:
// calculate spline function
// start: starting point of the movement
// ctrl1: 1st controll point
// ctrl2: 2nd controll point
// end: end point of the movement
// frac: value from 0 to 1 indicating where in the movement we are calculating
double Enemy::CalcSpline (double start, double ctrl1, double ctrl2, double end, double frac)
{
   double invFrac = 1-frac;
   return start*frac +
      ctrl1*3*frac*frac*invFac +
      ctrl2*3*frac*invFrac*invFrac +
      end*invFrac*invFrac*invFrac;

}

Step 3: implement the update function like so and remember to call it from your timer update function.

Code:
// Update function should be called every timer update to set
// the locationX and locationY values
void Enemy::Update(){
   // update frac
   frac += speed;
   if(frac > 1) frac = 1; // enforce upper bounds
   //compute new location
   locationX = CalcSpline(startX, ctrl1X, ctrl2X, endX, frac);
   locationY = CalcSpline(startY, ctrl1Y, ctrl2Y, endY, frac);
}

Step 4: be sure to draw your enemy sprite at locationX, locationY or all these calculations are for nothing

Step 5: Make an instance of the Enemy class and set its startX, startY, endX, and endY to positions off the screen. Play arround with the locations of the two "ctrl" point values untill you have a nice looking path. Also play arround with the speed variable. The speed variale should be no more than 0.1 or else the enemy will be too fast to see.

Step 6: Make multiple enemies and assign thier point values to what looks good. This may be a good place to read stuff in from a data file.

Hope this helps. If you want more help try posting your code.
Logged

Play my games at http://monkeydev.com/
muku
Level 10
*****


View Profile
« Reply #3 on: June 02, 2009, 09:09:45 AM »

Code:
   double startX; 
   double startY;
   double ctrl1X;
   double ctrl1Y;
   double ctrl2X;
   double ctrl2Y;
   double endX;
   double endY;
   double frac;
   double speed;

My refactoring sense is tingling! I'd recommend extracting all this stuff, as well as the CalcSpline method, into its own class, say SplinePath. Then you can create an abstract base class Path for it from which you can derive alternative implementations, say LinearPath, SinePath, etc.

The Enemy class would then just have a reference to a Path object which it uses every frame to update its own position; that way you can change an enemy's movement pattern simply by instantiating another kind of Path object, or you can even swap them out at runtime (say from an "attacking" path to a "fleeing" path).

I made a longer post about a slightly more general "componentized" approach to scripting actor behaviors here; I think something like that would work very well for enemies in a shmup.
Logged
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #4 on: June 02, 2009, 11:29:15 AM »

Code:
   double startX; 
   double startY;
   double ctrl1X;
   double ctrl1Y;
   double ctrl2X;
   double ctrl2Y;
   double endX;
   double endY;
   double frac;
   double speed;

My refactoring sense is tingling! I'd recommend extracting all this stuff, as well as the CalcSpline method, into its own class, say SplinePath. Then you can create an abstract base class Path for it from which you can derive alternative implementations, say LinearPath, SinePath, etc.

The Enemy class would then just have a reference to a Path object which it uses every frame to update its own position; that way you can change an enemy's movement pattern simply by instantiating another kind of Path object, or you can even swap them out at runtime (say from an "attacking" path to a "fleeing" path).

I made a longer post about a slightly more general "componentized" approach to scripting actor behaviors here; I think something like that would work very well for enemies in a shmup.

If nothing else, CalcSpline should be removed from the Enemy class and made a free standing function.  It never touches the this pointer, so it has no business being a member.
Logged



What would John Carmack do?
Kekskiller
Guest
« Reply #5 on: June 02, 2009, 01:31:31 PM »

If nothing else, CalcSpline should be removed from the Enemy class and made a free standing function.  It never touches the this pointer, so it has no business being a member.

Let's upgrade to C.
Hand Thumbs Up Left
Logged
Wilson Saunders
Level 5
*****


Nobody suspects the hamster


View Profile WWW
« Reply #6 on: June 05, 2009, 07:43:33 AM »

Caio the OP seems to be new to the whole programming thing. I did not want to complicate his project any more than necessary. The code I submitted was to get him started on using spines for NPC movement. Once he has the basics he can refractor and add scripting as he sees fit.
Logged

Play my games at http://monkeydev.com/
Aquin
Level 10
*****


Aquin is over here.


View Profile WWW
« Reply #7 on: June 05, 2009, 08:45:14 AM »

I guess that shows you just how many takes there are on smooth NPC movement.  The way I did it was pretty different.

For starters, I track the object's position(r), velocity(v) and acceleration(a) across the x and y axis.  I then update the velocity with the acceleration every frame (having a max velocity set.) 

For the enemy to change his motion, he'll have a list of motions.  After a certain amount of screen-time, he switches to his next motion.  So if you switch the acceleration along the y-axis to be negative, he'll pop in from above, slow down and then rise back up.

I also have special movements which allow him to move in a sin and a circle just by using the math library. 
Logged

I'd write a devlog about my current game, but I'm too busy making it.
Danmark
Level 7
**



View Profile
« Reply #8 on: June 05, 2009, 10:36:59 PM »

Thing is, right now the enemies' movement isn't fluid enough. The only way I know to change their movement direction smoothly is to increment or decrement the dirx and diry variables until they're around the value I want them to be, which is a very troublesome method for more complex movement patterns.
I may be misinterpreting your problem, but what you're doing by slowly changing dirx and diry is accelerating the enemy, because you're changing it's velocity. Problem is it's not a very practical or realistic way of doing it.

Your first step is a simple physics system. So do what Aquin said, keep track of position, velocity, and acceleration (just ask if you need pseudocode).
Logged
Akhel
Level 10
*****



View Profile
« Reply #9 on: June 08, 2009, 11:50:09 AM »

Thanks for all the helpful replies, guys. I am indeed somewhat new to programming, and this splines thing seems a bit overwhelming right now, so I think I'll settle for something simpler. All this info on the subject was definitely useful, though, and I'll keep it around for future projects.

The first alternative I thought of was to give every Actor a "direction" variable, which is expressed in degrees, and use it to determine dirx and diry. Then, when I wanted the Actor to move to a specific point, I'd call a function that takes a pair of coordinates and a number to represent the movement's "curviness". The function would calculate the angle between the Actor's current direction and the one it should be heading to get to the specified point, then change is direction by that angle divided by the curviness. It does work sometimes, but it doesn't behave as I expected way too often for me to use it.

So... what would be some other, simple way that would give me satisfactory results? I'm worried mostly about directions changing subtly and such things. toastie suggested sine waves, but I'm not sure what would be the best way to implement these.
Logged
Ivan
Owl Country
Level 10
*


alright, let's see what we can see


View Profile
« Reply #10 on: June 08, 2009, 07:59:27 PM »

So... what would be some other, simple way that would give me satisfactory results? I'm worried mostly about directions changing subtly and such things. toastie suggested sine waves, but I'm not sure what would be the best way to implement these.

Sine wave movement is really easy to do. You can use the sin() function in most languages. It will give you, for a specified X coordinate, a normalized value of Y, which you can then multiply by however wide you want your wave to be. So you move your object along X and then set its Y based on the sine value. (or vice versa if it's moving vertically). Does that make sense?
Logged

http://polycode.org/ - Free, cross-platform, open-source engine.
gnat
Level 1
*



View Profile WWW
« Reply #11 on: June 09, 2009, 04:04:06 AM »

Sine wave movement is really easy to do. You can use the sin() function in most languages. It will give you, for a specified X coordinate, a normalized value of Y, which you can then multiply by however wide you want your wave to be. So you move your object along X and then set its Y based on the sine value. (or vice versa if it's moving vertically). Does that make sense?
+1
I really like this idea! A very elegant way to implement wave-like movement.
Logged

LAN Party List - The definitive LAN party list. Also Game Jams, etc.
GitHub
Aquin
Level 10
*****


Aquin is over here.


View Profile WWW
« Reply #12 on: June 10, 2009, 11:40:01 AM »

Similarly, if you want circular movement about a specific point from your current point, you can combine the cos() and sin() functions handily.

Let me see if I can dig up a snippet of code that does such a thing.

        float dCos = cos(rotation);  //The angle amount to rotate.
        float dSin = sin(rotation);
        float ox = theShip->rx - centerX;
        float oy = theShip->ry - centerY;

        theShip->rx = (ox * dCos) - (oy * dSin) + centerX;
        theShip->ry = (ox * dSin) + (oy * dCos) + centerY;
Logged

I'd write a devlog about my current game, but I'm too busy making it.
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic