![]() |
|
Matching bullet start x,y with point on sprite that gets rotated |
Elvang
Member #7,828
October 2006
![]() |
I am currently making a space shooter game as a learning experience and am having trouble with matching up the bullet's start point and the point of fire on a sprite that rotates. I keep drawing a blank when I try to solve this problem, though I have a method that semi-works. If someone can point me in the right direction that'd be great. Also, does anyone know why I have to use itofix() on a fixed variable for use with fixsin() and fixcos()(Lines 37 and 38)? Code is below, not the best as I'm still learning. My temporary fix is on lines 134 to 147(end).
|
Jakub Wasilewski
Member #3,653
June 2003
![]() |
please note that I only skimmed through the code, so I might be missing something First, take the sprite without rotation. You decide on some coordinates (x, y) that is the origin for bullets. Now, when the ship rotates, the coordinates for this origin point should also rotate. The relevant equations are: x' = x cos(angle) - y sin(angle) Where (x', y') are the new coordinates of the point after the rotation by "angle". Please note that these equations are for the Y axis going up, like in standard math. On the computer screen, it's usually the other way, so you'll have to switch things around a little. About your itofix question, I'm not sure what is it that you have a problem with. itofix converts an "int" into a "fixed". Your angle variable is already a "fixed", so you can use it with fix***() functions right away. I strongly encourage that you just forget about fixeds, especially if you're learning. They'll just mess with your head. If you want to use them though, read the section of manual pertaining to them thoroughly. Anyway, I'm sure none of this makes sense, so wait until someone comes and translates --------------------------- |
Elvang
Member #7,828
October 2006
![]() |
Ok, after experimenting with it for awhile, I came up with this which is as close to it being accurate as I could get it. If I use (x,y) then the point of origin for the bullets goes all over the place. Also, if I don't do itofix(angle) then the value of x_trig and y_trig never change even though angle is already a fixed. On a side note, up to what level should I take math? I stopped after Pre-Cal as I didn't see anything I would ever use in the Calculus book. |
Ceagon Xylas
Member #5,495
February 2005
![]() |
Radians make this sort of thing much easier. I can't really tell what your code is trying to do... Wish I had more time to read over it, but I believe it's similar to what's happening in this post. Okay, radians are 0 to pi*2 for a full rotation. The rotate_sprite function does require a fixed however, so lets deal with that first. As for the bullet's initial position and velocity,
|
Elvang
Member #7,828
October 2006
![]() |
Power is back on, woot. Ok, I have converted over to radians and included math.h so I don't have to deal with fixed variables. I don't see how your solution determines the point of origin on a rotating sprite though. Heres my new code(does the same as above code but easier to read). Something is wrong with the formula used to determine the point of origin of the bullets still as they appear outside the bounds of the arena. Also, shouldn't sine be used with x and cosine with y on your formulas?
EDIT: Is the problem that my sprite is 17x31? |
Ceagon Xylas
Member #5,495
February 2005
![]() |
Quote: Also, shouldn't sine be used with x and cosine with y on your formulas?
Nope: Quote: Is the problem that my sprite is 17x31? Nope, you're simply going to change spawn_distance to the maximum width or height of your image. So spawn_distance=31; (May want to go with 32 to make it a little safer when finding it he bullet has hit anything) Sorry, I wasn't quite thorough in explaining the starting x and y of the bullet. Simply start at the center of your ship, move it to the outside of the ship, then set it's velocities. Something like:
Side notes: Using iterators with vectors will considerably speed up your program. I'd change this block if(bullet.empty() != true) { for(int i = 0; i < bullet.size(); i++) { bullet<i>.x += bullet<i>.vx; bullet<i>.y -= bullet<i>.vy; if(bullet<i>.x > x_res || bullet<i>.x < 0 || bullet<i>.y > y_res || bullet<i>.y < 0) bullet.erase(bullet.begin() + i); } } To for(vector<Projectile>::iterator i=bullet.begin(); i!=bullet.end(); i++) { i->x+=i->vx; i->y-=i->vy; if(i->x > x_res || i->x < 0 || i->y > y_res || i->y < 0) { //This simply swaps the bullet that needs to be deleted //with the last element in the vector and deletes it. //Much faster than resizing the entire vector. if(i<bullet.size()-1) memcpy(&bullet<i>,&bullet.back(),sizeof(bullets)); bullet.pop_back(); } }
|
gnolam
Member #2,030
March 2002
![]() |
Ceagon: You're still not rotating an arbitrary point, which (I assume) is what the OP asked for. Elvang: just follow Jakub's post, and make sure to ditch all that silly fixed point math and instead use floats/doubles and radians. -- |
Elvang
Member #7,828
October 2006
![]() |
Ok, using Ceagon's formulas(with some modification, for some reason the point was 64 radians(90 degrees) over what it should have been...) it works. When I first looked into how to go about getting rid of the bullets that went out of range I was going to use an iterator, but I have no experience with them. As such, I cannot decipher what is wrong with these two lines, even after extensive searching and reading if(i < bullet.size() - 1) memcpy( &bullet<i>, &bullet.back(), sizeof(bullet));
Heres all of my current code.
|
Ceagon Xylas
Member #5,495
February 2005
![]() |
Oh yuck, my brain totally pooped out on me. I mixed two ideas Here's the two ideas I was mixing: if(!bullet.empty()) { for(std::vector<Projectile>::iterator i = bullet.begin(); i != bullet.end(); /*nothing here*/) { i->x += i->vx; i->y -= i->vy; if(i->x > x_res || i->x < 0 || i->y > y_res || i->y < 0) { if(i!=bullet.end()) bullet.erase(i); } else i++; } } And
The last one's faster, but I'm not sure if it's buggy |
Elvang
Member #7,828
October 2006
![]() |
When it gets down to the last bullet in the vector the program now crashes with a "instruction at <insert address here> referenced memory at <insert address here>. The memory could not be 'read'." I'm guessing the iterator doesn't like all the erases? EDIT: Nvm, every time I go to reply your post has been updated heh... Yea, the second one crashes after 4 or 5 bullets exit the screen. Was about to say first one was also buggy until I noticed the increments location changed as well... Actually, the second one works now that I noticed that. |
Ceagon Xylas
Member #5,495
February 2005
![]() |
Hahaha I know, I'm such a lousy poster |
Elvang
Member #7,828
October 2006
![]() |
So for everytime I need to cycle through a vector similar to this and possibly remove certain elements should I use that code? Example of implementation for a lifespan for projectiles(Didn't want to repost entire source so I started at while and cut it off right after if(!bullet.empty())'s closing brace). while( speed_counter > 0) { if(!bullet.empty()) { for(std::vector<Projectile>::iterator i = bullet.begin(); i != bullet.end();) { i->lifetime++; if(i->lifetime >= i->life_max) { memcpy(&(*i),&bullet.back(),sizeof(Projectile)); bullet.pop_back(); } else i++; } } EDIT: Nvm, just added in an extra check and variable increment to the existing for loop. |
Ceagon Xylas
Member #5,495
February 2005
![]() |
Yes, I'm pretty sure you could use that code every time you needed to find specific elements inside the vector and remove them. As long as the element meets the condition (in this case, i->lifetime>=i->maxlife) it'll be switched with the last element in the vector and then deleted. By the way, if(!bullet.empty()) isn't necessary. If the vector's empty then i=bullet.end(), and the for loop will end immediately |
|