Moving character over terrain in a straight line

Blitz3D Forums/Blitz3D Beginners Area/Moving character over terrain in a straight line

PowerPC603(Posted 2012) [#1]
Hi guys,

I've got a problem but I don't know how to fix it.

I've made a terrain mesh in 3DS Max and imported it succesfully in Blitz3D.
Then I made a test-character (just a sphere) which should move in a straight line towards an end-point.

I've made the terrain mesh pickable and wherever I click on the terrain, the end-point is indicated by another sphere.

When I click the terrain, the end-point sphere is created correctly and the character moves automatically towards this point using PointEntity and MoveEntity.

However, the character doesn't move in a straight line towards the end-point when it encounters a hill.

Since the MoveEntity command pushes the character against a hill, it's forced a bit upwards, but also a bit sideways due to collisions with the terrain mesh.
So, the character moves in curves towards the end-point, which isn't what I need.

The character should move in a straight line even if it encounters a very steep hill.

I'm planning to use collision-meshes afterwards to prevent the character moving up some hills where he isn't supposed to go.

Just like in most MMORPG's, where you can use the arrow keys or click on the terrain to go towards that point.
In those games, the character moves in a straight line, running at the same speed all the time.

I was thinking about creating pivots to which the character is attached to.
Then I would move this pivot towards the end-point and it would drag the character along.
But I think this won't keep the character in a straight line either, as the character itself still collides with the terrain and gets pushed aside even when the pivot moves straight ahead.

How is this done properly? I'm thinking about this problem for a few days now and I can't continue without a solution.

This is for a MMORPG-like game (like WoW), but it will be single player only and it won't be as big of course.
But it will feature many aspects of such a game:
- killing monsters to gain experience and acquire loot
- trade with NPC's and craft equipment so you get more defense (better armor) and better attack (better weapon) so you can kill higher level monsters
- do quests to gain additional experience and unique equipment
- mining to get some ore (required for upgrading your gear)
- it will have a long main storyline with many side-quests
- ...

The monsters you need to kill to gain experience would use the same movement,
so it would be really weird if you attack a monster and it comes running towards you as if it's drunk
(moving in a curved path instead of a straight line because he's colliding with the hills on the terrain which push him sideways).

I've created a small example (it uses 3 textures of the xfighter demo which comes with Blitz3D).
It shows you what's happening. Somewhere, there's a red sphere, this is the character.
Just click anywhere on the terrain, there will appear a white sphere as target where the character should move towards in a straight line (but he runs there in a curved line because of collisions):


Last edited 2012


Kryzon(Posted 2012) [#2]
Try this:

[EDIT: Updated]


Last edited 2012


PowerPC603(Posted 2012) [#3]
This works perfectly, just as I needed it.

I've never used TFormPoint before, so I'll try to figure things out how it really works.

Would this cause much of an issue towards performance when 25 monsters are following you, each using a linepick every frame to calculate it's new position?



I've written this test code in B3D, but I'm gonna create the game using BMax + Xors3D.
It allows me to maintain my types better later on when I have alot of different object-types (weapons, armor-pieces, ammo, loot, ...).


Kryzon(Posted 2012) [#4]
Actually, it can be faster. I was using LinePick because TerrainHeight was giving a freaky result.

I read a bit and this TerrainHeight command is not best suited for what I wanted. We should be using TerrainY (which returns the transformed terrain's Y height at a certain world location).

So in that sample above, overwrite these two lines:
LinePick(TFormedX(),250,TFormedZ(),0,-250,0)
tempY = PickedY()
with this single one:
tempY = TerrainY(terr,TFormedX(),TFormedY(),TFormedZ())
It runs the same, should be faster and you can use later on under Xors3D with the xTerrainY equivalent.


Also, just to see the sample really go to town, scale the terrain like this:
ScaleEntity terr, 15, 450, 15
...instead of the original "20, 250, 20" (I've updated the sample with all these changes).

Last edited 2012


PowerPC603(Posted 2012) [#5]
I've only used the terrain to show the problem. Uploading the actual mesh would need you to download another file to test my example.

The real game won't use Blitz Terrains, but actual meshes, created in 3DS Max.
I'll stick to the linepick in that case. TerrainY won't work with that.

On the terrain (or landscape mesh), there will be buildings, trees, rocks and other stuff as well, like the stuff all these kind of games have.

I only need to put it in a method, so it's easier to use for any monster or character.


PowerPC603(Posted 2012) [#6]
After testing some new code (adding 5 monsters to the map), which uses the same approach (using a linepick to determine the height where the monster should be positioned), performance drops significantly.

When the monsters are on their spawn-point, just idling, fps is about 320 fps.

When the player comes near them, they are put in a follow-player mode, where they use the linepicks for their movement.
Fps drops to about 64fps with only 5 monsters on the map.

I'll need a few 100 monsters on the same map (but they won't follow the player all the time). But there may be cases where there are 10-20 monsters moving at once, all attacking the player.

Currently, I only have a map (size 1000x1000) which is one huge mesh (about 20.000 triangles).
I have one player (only a sphere object) and 5 monsters, which are also spheres for now.
Nothing is animated yet, so that will take a performance-hit as well later on.

I'll have to find a new approach or revert back to collisions if all other approaches are performance-hitters, and take the side-effects like side-shifting of the monsters while they move.
It could be something special, so the monsters seem to take the easiest path (running around hills instead of over them).

I wonder how other games of this type do this efficiently, processing over a few hundred monsters at once without a big performance-hit.

Also, I cannot put all coordinates in a look-up table as the maps are too huge for this. It would eat a few 100Mb of RAM just for those coordinates to make them accurate enough.

EDIT:
Just tested with 20 monsters.
When they are all following the player, fps drops to 20fps.
When they are in idle-mode, fps is about 280fps.
This can be before the player came close to them, or after they chased the player but lost him (player got too far away and they run back to their spawn-point).

Last edited 2012


Guy Fawkes(Posted 2012) [#7]
Interesting bit of code :)


Rob the Great(Posted 2012) [#8]
Here's an odd way of doing it. Picture that you are going to point the Char sphere at the target sphere, lift it 100 meters into the air so that collisions are not a factor, move it towards the target, and then bring it down 100 meters so that it is touching the ground again. You don't see the up and down movement, but it achieves a straight line like you are wanting.

Let me know if this helps. Hopefully, the time is ok for more enemies. It takes about 1 millisecond on my machine, but my machine is slow.

Last edited 2012


Kryzon(Posted 2012) [#9]
Yo!

I wonder how other games of this type do this efficiently, processing over a few hundred monsters at once without a big performance-hit.

@PowerPC603: One thing you might want to do is split your terrain into several chunks in your modelling application (each being a different object, but all with the same brush).
If you send a single mesh with tons of polygons Blitz3D will test each one against the ray for picking.
I'm thinking with several chunks, Blitz3D will first test if the ray intersects each chunk's bounding-box, then proceed to deep polygon testing.
This may improve things a bit. With your 20k poly level you can start at a number of 20 chunks and see how things go (in 3DS Max it's a matter of selecting polygons and clicking Detach -> To Object until you have 20 objects that represent the whole level together).

Not only that, but when you get to Xors3D + BMax make sure to use the physics engine to do the picking. Blitz3D's ray\line picking may be a bit slow and may not have the same optimizations that a fully dedicated physics engine accumulated through time.


PowerPC603(Posted 2012) [#10]
@Kryzon,

I already moved to BMax + Xors3D to use type-methods to do everything.
Xors3D's linepick seems to be slow as well. The fps mentioned above was with BMax + Xors3D.
I'm not really familiar with physics engines (I think they use alot of high-level math, correct me if I'm wrong). I wouldn't know how to set things up.

I was thinking about the same idea to move the player up, then forwards and then drop his back down onto the terrain using plain collisions.
After alot of error and trial, it works as good as the linepick, only alot faster.

I applied collisions again (the terrain has type 1, the monsters have type 2).
The response for the collisions is STOP.
Using the other responses still resulted in the monsters being pushed sideways when translating them downwards.


This is my code now using BMax + Xors3D.

Both UpdateWorlds are needed apparently to get the proper results.
Now it processes 50 monsters at 155fps when they're moving (following the player or returning to their spawnpoint).
When they are idling, I have 185fps.
So not a big performance loss anymore.

Each monster also has a sphere to indicate it's return-point, which will be replaced by a pivot of course.

So, with 50 monsters in view and the player (also with his target-point), I'm rendering 102 sphere's (50 monsters, 50 return points, the player and his target point) and a big landscape.

Last edited 2012

Last edited 2012


Guy Fawkes(Posted 2012) [#11]
Um, just wondering. isnt this supposed to be Blitz3D ONLY? :)


PowerPC603(Posted 2012) [#12]
This test started using B3D and it gave me about the same results.


Yasha(Posted 2012) [#13]
I wonder how other games of this type do this efficiently, processing over a few hundred monsters at once without a big performance-hit


I think you'll find it's very rare to actually use collisions for this sort of thing. It's much, much easier to ditch the collision system, move your characters in X and Z as though on a grid, and get their Y using simple, pure mathematical operations. If you need them to collide with or at least avoid each other too, you can use a very simple radial system.

(Of course I say this without knowing what else you want to use collisions for, but if all they're doing is stopping things going through the floor, you would do a lot better to not use them at all, as what they're intended for is correctly applying the sliding movement.)

Also, Blitz3D's collision system is quite slow by the standards of other, newer physics engines and collision systems, and you may experience quite a speed up just from moving.


isnt this supposed to be Blitz3D ONLY? :)


You jealous or something?

Xors3D is directly based on Blitz3D's command set. This is the best place on the Blitz forums to discuss it.


Guy Fawkes(Posted 2012) [#14]
Well exCUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUSE me, princess -.-


I was just asking -.-


Kryzon(Posted 2012) [#15]
I'm not really familiar with physics engines (I think they use alot of high-level math, correct me if I'm wrong). I wouldn't know how to set things up.

Their purpose is to make all the calculations for you, so you're only required to set things up such as values and create bodies (it's painless, minimal testing required).
These engines are especially useful when they come bundled with a game engine such as Xors3D, which means they are totally integrated with how it works.

In this case Xors3D uses Bullet, a tried-and-true physics engine used in several AAA games, so you can totally rely on it. It's lightning fast.

I'm glad it's working with the collisions, but in that case you're spending two transformations (the Translates), plus the double calls to UpdateWorld (also take a look at xResetEntity, might be good).
You'll need this performance later on for animations and AI.

Using Bullet, you'd just need a Trimesh rigid-body for the environment and then you'd be ready to raycast it, which is the equivalent of LinePicking (I'm sure this is documented or exemplified with Xors3D).
Then retrieve the raycast contact information from Bullet and use these values. You can even keep using Xors3D native collisions with it.


PowerPC603(Posted 2012) [#16]
Yes, collisions in my game will be used to prevent the monsters (and your character) from falling through the ground.

They will also be used when I have buildings, rocks, trees and alot more stuff on the map.
So all these things would need collisions as well.

After all, I would still need collisions when I have a collision-mesh to prevent monsters/players moving up/down a hill where they're not supposed to come.
The character is not supposed to be able to fall down a cliff or walk up very steep hills (over 60 degrees upwards).
So it's easy to use a collision-mesh (just vertically positioned quads, all merged together in one single mesh) to block certain areas.

Doing all these checks using maths would make the code huge (as you need to calculate your position against everything else in the world).



No offense, but I'd rather use collisions which give me a good performance instead of calculating the position of a monster with poor results, even if it's not the "default" way of doing it.

I cannot sell it when the game is running at 5fps with the excuse that I've used mathematical calculations to prevent bugs instead of standard collisions, just because it's THE way to do it.


Xors3D is directly based on Blitz3D's command set. This is the best place on the Blitz forums to discuss it.


My thought exactly.
There is no sub-forum for BMax using Xors3D, and asking this in the BMax forums isn't correct either, as it has more to do with Blitz3D than BMax, given the nature of the topic (3D collisions or calculations).


I'm glad it's working with the collisions, but in that case you're spending two transformations (the Translates), plus the double calls to UpdateWorld (also take a look at xResetEntity, might be good).
You'll need this performance later on for animations and AI.


I tested some more and I could already get rid of the second UpdateWorld.
Won't ResetEntity clear the collision-data from the entity?

EDIT: just tested by adding xResetEntity.
Removing the first xUpdateWorld and putting xResetEntity instead works as a charm as well.
Now both xUpdateWorld commands are gone.

There is only one left in the main loop, executed only once per frame.



Since this game is still in a very early development status, I could spend some time to learn how to use physics.
I could make a backup of the current code and try to get it done with physics.



I wanted to make a game like GTA, combined with some features of X3: Terran Conflict (a 3D spacegame, made by Egosoft).
To build a big world where the player could do missions and build his own factories to make his own products and sell them to the AI.
But it seemed to difficult because of all the physics any vehicle would need.

Since I also like to play games like WoW, LineAgeII and RF Online, it seemed easier to make a game like that.
It would only involve simple collisions to prevent the player and monsters falling through the ground and to collide with buildings and other stuff like trees and rocks.

Last edited 2012


Yasha(Posted 2012) [#17]
collisions which give me a good performance instead of calculating the position of a monster with poor results


Um... I think you took the opposite of what I meant...

The mathematical solution would be faster, since it would involve doing less work (collisions after all use the same logic, they just do it within the B3D/Xors library), and would be more accurate since you wouldn't have to deal with the sliding issue that's been a problem for you so far.

The thing with game development is actually very much not to find the rigorously "correct" solution, but to find the fastest way to cheat and get approximately suitable results. I agree entirely with your desire to ship something fast!


So the obvious area where we can ask the "How can we cheat?" question is: do we really need three dimensional collisions for this game engine? For GTA, yes, you need a full physics system for all objects (since cars will spin in midair and whatnot). If we assume you're going for the WoW route though... in truth, no you don't really need a 3D system.


Note this:

I would still need collisions when I have a collision-mesh to prevent monsters/players moving up/down a hill where they're not supposed to come


If you want to stop people moving over cliffs in both directions, then you're already moving away from the idea of full 3D simulation. The type of game this sounds like it's describing would be more suited to having an invisible "map" built with 2D boundaries. You could then simulate the characters' movement in X and Z using this invisible map and a 2D physics engine, and use a completely separate heightmap-based system for placing them in the Y.

It's not a serious suggestion that you should make the game this way (you'd need to do something else for buildings), but to point out that the most generic toolset - the 3D collision engine - shouldn't constrain your design process. Generic tools are always the slowest, but you can always come up with something better.

Last edited 2012


PowerPC603(Posted 2012) [#18]
The gameworld won't just be a 2D terrain with some slopes on it.
There could also be buildings where you can walk through on several levels or even on the roof.
Bridges will also be there to allow the player to move over a cliff.

There will also be caves underground where monsters live, as well as on the surface (right above the cave, or even several caves below eachother, each one connected by tunnels or corridors).
Using a 2D boundaries map would block a player inside the cave from running up a stalagmite somewhere, that would be good.
But it would also block the same 2D area on top of the cave (the surface of the world) where everything is nearly flat and passable.

So, using a 2D physics engine and calculating the Y won't help in this case, as there will be multiple Y-values on some locations.


I tried using maths (isn't linepick pure math?), but the results were alot slower than using collisions.
Linepick with 20 monsters following the player = 20fps (only one linepick per monster per frame).
Collisions with 195 monsters following the player = 27fps (just tested).

Or are you talking about other math which doesn't involve linepicks or something similar?

Last edited 2012


Yasha(Posted 2012) [#19]
Or are you talking about other math which doesn't involve linepicks or something similar?


Yeah, I just meant get the Y heights of the vertices of the triangle the character is standing on, and use the character's X and Z to get their height on said polygon interpolated between the corners. This is based on your statement much higher up that you had a "terrain mesh", indicating a regular grid (it would work without a grid too, just be a little less efficient since you couldn't simplify everything assuming you know where the verts are). This is more or less what the TerrainHeight function does with builtin (non-mesh) terrains.

LinePick by contrast is quite a slow command (counts as part of the collision system, by the way - it uses the same backend)... but this is only true of the Blitz3D version so you may well find other collision engines give a massive speed boost to your existing setup. (I would expect Bullet, as suggested by Kryzon above, to be pretty good at this.)

Last edited 2012


PowerPC603(Posted 2012) [#20]
I've just tested it again with 190 monsters, using the physics.
It was actually very simple to setup, just as Kryzon said.

I just applied xEntityAddTriMeshShape to the terrain mesh.
Every frame, the monster uses this code to perform it's movement:
				' Calculate monster's next position based on speed
				xTFormPoint 0.0, 0.0, MonsterType.MovingSpeed, Entity, 0
				x = xTFormedX()
				y = xTFormedY()
				z = xTFormedZ()
				xPhysicsRayCast x, y + 5.0, z, x, y - 5.0, z
				' Move monster to new position
				xPositionEntity Entity, x, xPhysicsGetHitPointY(), z


It checks the terrain from 5 meters above and below the monster's calculated 2D movement, using a raycast.

Now, when the monsters are idle at their spawn-point, I get 70 fps. I'm rendering 383 surfaces at the screen (190 monsters, 190 spheres for the return points, 1 player, one sphere for the player's target position and the terrain itself).
The raycasting doesn't do anything yet, because that code isn't in the idle-state.

When I get close to a monster, it changes it's state to "follow", which uses the raycast to determine it's position.

The result is remarkably: absolutely no drop in fps.
It stays at 70fps, even when all 190 monsters are raycasting the terrain to determine their position every frame to follow the player.
Using collisions, my result dropped to 27fps using 195 monsters. So physics are even better than collisions.

Thanks for the idea and a little knowledge on how to get started using the physics stuff, Kryzon.


After replacing the return-point spheres by pivots, fps went even higher to 120fps. Which also stays the same in both idle state and follow state of all 190 monsters.



I wonder why linepick is so damn slow and a raycast is extremely fast.
I even don't have multithreading enabled (I don't know if it would give a speed boost).

Correct me if I'm wrong, but from what I understood about reading something about raycasting, is that models are actually split up in octrees.
My guess would be that each branch (the smallest part of the octree) or whatever they are called, of the octree holds only a few polygons.
And where linepick scans the entire mesh, raycast could only scan the branches where the ray exists. Maybe that could explain why raycasting is alot faster than linepick.

It doesn't really matter how it works. The most important thing is to get fast code and the proper results :)



I could still use the normal collisions for bumping into buildings, rocks, trees and all the other stuff if needed.

Last edited 2012


Kryzon(Posted 2012) [#21]
Wow, that's awesome! I didn't know it'd be that fast. Congrats on getting it to run.


Blitzplotter(Posted 2012) [#22]
Very interesting thread, been toying with an idea which requires this kinda lgic, thx.


PowerPC603(Posted 2012) [#23]
I also didn't expect a raycast to be that fast. It's doing 190 raycasts per frame, without even 1 fps performance-hit. Talk about speed of physics engines.

Of course, the player won't be able to engage 190 monsters at once to fight them during the entire game.

But I definately need high amounts of monsters to fill the map (between 100 and 500 monsters, based on the layout and size of the map).
There will be added checks to prevent processing monsters on the other side of the map (which are too far away from the player).

At some point, there will be a large amount of monsters near the player (about 50).
I'm planning an event in the game where, at certain intervals, packs of monsters attack your home town.
In the beginning, there won't be many monsters and they will be weak, but later on, the strength and amount of monsters will go up.
The home town will have automatic defense towers at the gates which can hold off a few monsters, but as the game progresses and the player becomes stronger, he'll have to fight to help protecting the town and avoid an invasion.

It's only during such an event where the player will have large amounts of monsters near his location, all moving and doing stuff like attacking the gates, the player or other NPC's in town.

Last edited 2012


PowerPC603(Posted 2012) [#24]
I did some more testing to compare linepicks between Blitz3D, BMax + Xors3D and physics raycasting.

Blitz3D code:


BMax + Xors3D code:


BMax + Xors3D using physics:


With this quick test, I got these results:
Blitz3D using 1000 linepicks on the terrain: 8ms
BMax + Xors3D using 1000 linepicks: 2240ms
BMax + Xors3D using 1000 raycasts: 7ms

So it seems Xors3D's linepick is way slower than blitz3D's linepick.
B3D's linepick seems to be as fast as Xors3D's (or better, Bullet's) physics engine.

Last edited 2012