To anyone who understands programming logic/code/GML...Help!

A place for people with an interest in developing new shmups.
Post Reply
User avatar
ForteMP3
Posts: 178
Joined: Tue Feb 01, 2005 3:15 pm
Location: Somewhere in the Midwest.

To anyone who understands programming logic/code/GML...Help!

Post by ForteMP3 »

Well, sadly I think making a 100% 'smooth' movement system for a shmup is next to impossible, given the fact moving at high speeds will always be choppy. Moving at slow speeds is really the only way to have movement appear to be smooth. But that's not what I'm posting about...

Remember when I mentioned someone ported BulletML to GameMaker 6? ...Turns out there's something in his code far more valuble than its BulletML scripts. It's the collision detection script. It compensates for one of GameMaker's biggest flaws, the fact objects won't collide if they move past each other but don't actually meet.

Here's an example. Let's say we have Vic Viper, and an enemy bullet. For some bizarre reason, let's say Vic Viper's moving a speed of 50 pixels per frame. This means one tap of a direction will move Vic Viper 50 pixels, instantly. Anything between the start and end of those 50 pixels is ignored. So if a bullet's in there? Well, no collision is registered, because technically they never collided. This means that normally, you would need to either have a large collison mask, or just move relatively slow to always ensure collisions register.

...This BulletML demo changes all the rules. As far as I can tell, it will ALWAYS register a collision, even if you 'jump' the coordinates of a bullet. The only problem is that the code for this process is quite complex, and I can't understand it.

The following code is in the step event of the player ship. For non GM users, the step event is an event that's processed during every step/frame of gameplay. This event is typically used for code that should always be executing. // denotes comments. If the comments are quotes, then they're ones I've inserted, and not the original programmer.

var _dx,_dy,_myspd ;
_dx = 0 ; _dy = 0 ;

// check keyboard
if(keyboard_check(vk_left)) _dx = -1 ;
if(keyboard_check(vk_right)) _dx = +1 ;
if(keyboard_check(vk_up)) _dy = -1 ;
if(keyboard_check(vk_down)) _dy = +1 ;
if(keyboard_check(vk_shift)) {myspeed = 4 ; } else{ myspeed = 200 ;}
//"Normally the second speed is 8, not 200. I set it to a rediculously high value to see just how accurate this system was. It's incredibly accurate, even at this high speed. _dx and _dy appear to be related to movement and collision detection in the block of code below."

//"isReady is a variable/flag that determines if the player ship can be hit or not. It's your basic invincibility when respawning"
// advanced collision judge
if (!isReady){
_myspd = myspeed*sqrt(abs(_dx)+abs(_dy)) ;
with(obj_BulletML){
if( distance_to_point(other.x,other.y) < speed+local._myspd ){
var _colflg , _cnt , _bdx , _bdy , _d ;
_d = ceil(speed+local._myspd) ;
_bdx = cos(direction*DEGTORAD)*speed/_d ;
_bdy = -sin(direction*DEGTORAD)*speed/_d ;
_colflg = false ;
for(_cnt = 0;_cnt<_d;_cnt+=1 ){
other.x += local._dx*other.myspeed/_d ;
other.y += local._dy*other.myspeed/_d ;
if(instance_place( x+_bdx*_cnt,y+_bdy*_cnt,other.id)){
with(other) event_perform(ev_collision,obj_BulletML) ;
_colflg = true ;
break ;
}
}
other.x = other.xprevious ;
other.y = other.yprevious ;
if(_colflg)
break ;
}
}
}
//"As far as I can tell, this seems to do a lot of various checks during movement to see if a collision could register as if the movement was smooth and from pixel to pixel, instead of the jump based movement GM6 uses. This is what I REALLY need help understanding."


// moving
x += _dx*myspeed ;
y += _dy*myspeed ;
//"This seems to make sense, though it's not how I'd usually code my movement."

// must be in the room.
if(x<0) x=0 ;
if(y<0) y=0 ;
if(x>room_width) x=room_width ;
if(y>room_height) y=room_height ;
//"This is a simple code most shooters use to keep the ship from exiting the room boundaries. I don't really need help with this."

If you need to see the actual source/GM6 file, look for my BulletML post on this forum, it has a link to the BulletML demo for GM6. Obviously, you need GM6 to view the code.
YOU ARE APPROACHING THE TARGET OF ATTACK! THE MISSION STARTS NOW! ARE YOU READY?!
User avatar
raiden
Posts: 862
Joined: Tue Jan 25, 2005 11:41 pm
Location: Cologne
Contact:

Post by raiden »

Well, sadly I think making a 100% 'smooth' movement system for a shmup is next to impossible, given the fact moving at high speeds will always be choppy. Moving at slow speeds is really the only way to have movement appear to be smooth.
does this refer to Gamemaker shmups only, or to professional games as well? I´m asking because I´m wondering what your concept of smoothness is. It might just depend on framerate.

I´m not familiar with Gamemaker code, so here´s a few questions:
what does _ before a variable name mean?
what does if () {with(other) ... } do?
what´s the meaning of "other"? Is it just the way the code´s author named his variables, or is it a specific term in Gamemaker code?
User avatar
fog
Posts: 38
Joined: Fri Feb 18, 2005 5:13 pm
Location: Newcastle, England
Contact:

Post by fog »

Firstly the smoothness of the movement will always to some extent be linked to the frame rate. Therefore always use timer based movement to allow for any fluctuations in the frame rate. This wont smooth the movement but it will ensure it's always a constant speed which looks so much better.

Also I'd guess (as I don't use it) that BulletML either does the collisions using vectors or simpler line intersection maths to calculate whether 2 objects paths will cross.

A simpler but slower way for you to do this would be to move the objects in small ammounts and do the collisions but don't draw every frame. This would keep the frame rate high as simply doing the maths for the smaller steps and not updating the graphics should be very quick.
User avatar
ForteMP3
Posts: 178
Joined: Tue Feb 01, 2005 3:15 pm
Location: Somewhere in the Midwest.

Post by ForteMP3 »

Anyone who uses GameMaker will tell you that Framerate doesn't have much of an effect on movement. 30 or 60 frames won't change the 'jumpy' movement used by GameMaker. As I've said, all movement is read as 'Instantly move to point.'

As for the _ before variables, I think that's just the programmer's preference.

The with statement is basically a way to quickly refer to something in code that follows. {} are brackets used for blocks of code, one use is for having several lines of code execute for one if statement. "Other" refers to the other object involved in a collision, it's basically a way to manipulate that object without having to find details like its index.

Here's an example of the With statement

with(objBullet)
{
speed=5
direction=270
}

This would set every instance of objBullet to have a speed of 5 and direction of 270.
YOU ARE APPROACHING THE TARGET OF ATTACK! THE MISSION STARTS NOW! ARE YOU READY?!
dboeren
Posts: 137
Joined: Sun Jan 30, 2005 3:09 am
Location: Atlanta, Georgia

Post by dboeren »

Yeah, looks like they are breaking your movement into little pieces and then checking for a collision each step of the way.

Here, they determine your speed, and store it in _d. _dbx and _bdy are how much x and y we move in a single pixel of travel. We just precalculate them here to save time.

_d = ceil(speed+local._myspd) ;
_bdx = cos(direction*DEGTORAD)*speed/_d ;
_bdy = -sin(direction*DEGTORAD)*speed/_d ;


Here, they count 1 pixel at a time from 0 to _d (your speed) and
check for a collision each step of the way.

for(_cnt = 0;_cnt<_d;_cnt+=1 ) {
// Here we calculate where the bullet would be at this stage
other.x += local._dx*other.myspeed/_d ;
other.y += local._dy*other.myspeed/_d ;

// Here we check the actual collision
if (instance_place( x+_bdx*_cnt,y+_bdy*_cnt,other.id)) {
with(other) event_perform(ev_collision,obj_BulletML) ;
_colflg = true ;
break ;
}
}

Sounds like "other" is probably the name of the object you are checking collision against, ie - it's the bullet.

Starting a variable name with an underscore like "_d" is an old convention sometimes used to denote that a variable is purely internal. That is, it's being used temporarily inside some routine and its value is never visible outside of that code. In this case, it's just sort of a scratchpad for some calculations.

The "with" statement in some languages (Pascal, for example) gives you access to an object's internal variables without having to name the object. It's sort of a laziness thing, and personally I never liked it because it makes the code harder to read. The idea is instead of saying this:

other.x = blah
other.y = blah
other.speed = blah

you can say this:

with (other) {
x = blah
y = blah
speed = blah
}

And it knows that if you are talking about some variable inside that with() block that doesn't exist, it's actually part of "other".

There are probably better ways to do collision detection, but this will work and is quite thorough. Getting huge speedups out of it will usually involve making some assumption like "bullets have no area" or allowing a slight sloppiness in detection. For example, instead of stepping 1 pixel at a time, step 2 or 3 pixels at a time. Depending on the size/shape of the bullet, this may not even lose accuracy. Plus, I have no idea if GameMaker does just rectangular collision or if you can specify a transparency mask of some kind to make the bullet round.
Currently playing: Gunbird 2 PCB
User avatar
shiftace
Posts: 435
Joined: Tue Jan 25, 2005 10:18 pm
Location: yes

Post by shiftace »

dboeren explained the collision check nicely.
ForteMP3 wrote:Anyone who uses GameMaker will tell you that Framerate doesn't have much of an effect on movement. 30 or 60 frames won't change the 'jumpy' movement used by GameMaker. As I've said, all movement is read as 'Instantly move to point.'
What matters isn't the game's framerate, it's the "input framerate," i.e. how often the game checks for keyboard input. It -should- check at every graphics frame, and then your movement will be as smooth as the bullets'. When I played with your earlier demo, it looked like the bullets were being animated smoothly, let's say at 60 fps, but the ship seemed to move at only 15 fps.

"Instantly move to point" will look totally smooth if the moves occur at 60 fps.
User avatar
fog
Posts: 38
Joined: Fri Feb 18, 2005 5:13 pm
Location: Newcastle, England
Contact:

Post by fog »

ForteMP3 wrote:Anyone who uses GameMaker will tell you that Framerate doesn't have much of an effect on movement. 30 or 60 frames won't change the 'jumpy' movement used by GameMaker. As I've said, all movement is read as 'Instantly move to point.'
Actually even in Gamemaker framerate does have a huge impact on movement.

When not using timer based movement objects at 30 fps will move half as fast as objects at 60 fps. Now if you experience variable frame rates (eg. with lots of on screen action or on slower PC's) then the movement speed will vary and look choppy.

I know it's not exactly what you meant by "jumpy" but it does have an effect. :)
User avatar
nullpointer
Posts: 66
Joined: Tue Jan 25, 2005 11:12 pm

Post by nullpointer »

there are 2 main ways to control movement and framerate in games programming..

1. the hard way: calculate the movement over a specific period of time (10ms for eg) you require and then multiply/divide that by the framerate.
This way your program will take advantage of a fast PC with higher framerate drawing by using every frame to move objects smaller distances (ending up smoother but still the same speed). and will move objects greater steps for slower framerates..

2. the easy way: assume a bas fps rate (say 30fps) and cap your movement updates to this limit.. This means that any PC capable of writing more than 30fps will not benefit in a smoother animation, but it is much easier to calculate and the only issue will be slower PCs that will slow the whole system down.(however if you pick a sensible middle rate this shouldnt be too much of an issue)

The problem also comes that as you add other graphic elements to your game the framerate will automatically slow down (alpha sprites or lots of overdraw etc). SInce you cant predict exactly how much this will effect a game, start with a basic FPS and allow different level of details if you want to cope with slower machines that cant even manage yr base rate.

To be honest most people wont notice the difference between framerates as long as they are about TV refresh speed or higher (25fps). It may make your game smoother but it wont really effect the gameplay.

As mentioned above. if your stepsize is too big (ie the movement of an object per frame or per input) the object may step over an enemy craft completely and the collision undetected. You can either do clever interpolation routines to check all the positions inbetween (tricky stuff) or decrease the step size and up the FPS. With newer PCs this is no problem. You will find that on old PCs it might be more difficult. But notice that older games also had much smaller resolutions so step sizes were also smaller (but in scale similar)
Post Reply