• Advertisement
Sign in to follow this  

Unity 2D Projectiles Continued

This topic is 4273 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Well my old thread has since been retired unfortunately so I have to make a lousey link to it so people will know what Im talking about lol here ya go: old forum That's the link. The problem is still the same! Bullets don't function properly. New varation of the problem however. Now we have two things happening depending on what I do to the code: When the bullet goes past the visible left or right hand side of the screen it disappears naturally. However, upon hitting the left side the bullet freezes in animation but I can still move around. Second: If I switch | with & in this code
if(Bullet.getx()<0 | Bullet.getx()>640){


the bullet will just go past the screen with no problems. BUT! In both cases said bullet does not seem to delete itself from the linked list I have to track the bullets! I am not able to fire more than one bullet when I should be able to shoot up to 20. Here's the bullet code for your reading enjoyment:
#define BULLETS 20

Sprite Bullet[BULLETS];

struct bullet{
  float x;
  float y;
  float xvel;
  float yvel;
  int direction;
  bool dead;
  bullet *next;
  bullet *previous;
  };  
  bullet* first_bullet = NULL;
  bullet* current_bullet = NULL;
  
int bdraw[BULLETS];

bullet* NewBullet()
{
 for(int i=0;i<BULLETS;i++){
 if(bdraw == 0){
  if(first_bullet==NULL)
  {
    first_bullet=new bullet;
    current_bullet=first_bullet;
    current_bullet->direction = face_right;
    current_bullet->x = mario.getx();
    current_bullet->y = mario.gety();
    current_bullet->xvel = Bullet.getSpeed() * current_bullet->direction;
    Bullet.set(current_bullet->x += 1, current_bullet->y += 0);
    current_bullet->next=NULL;
    current_bullet->previous=NULL;
  }
  
  else
  {
    current_bullet->next=new bullet;
    current_bullet->next->direction = face_right;
    current_bullet->next->x = mario.getx();
    current_bullet->next->y = mario.gety();
    current_bullet->next->xvel = Bullet.getSpeed() * current_bullet->next->direction;
    current_bullet->next->previous=current_bullet->next;
    current_bullet=current_bullet->next;
    Bullet.set(current_bullet->x+=1, current_bullet->y+=0);
    current_bullet->next=NULL;
  }
  bdraw = 1;
  }
  }
  current_bullet->dead=false;
  return current_bullet;
  }
    
void DeleteAllBullets()
{
  bullet* this_bullet=first_bullet;
  bullet* dead_bullet=NULL;
  while(this_bullet!=NULL)
  {
    dead_bullet=this_bullet;
    this_bullet=this_bullet->next;
    delete dead_bullet;
  }
  first_bullet=NULL;
  current_bullet=NULL;
}

void RenderBullet()
{

  bullet* this_bullet=first_bullet;
  bullet* dead_bullet=NULL;
  while(this_bullet!=NULL)
  {
    if(this_bullet->dead)
    {
      dead_bullet=this_bullet;
      this_bullet=this_bullet->next;
      if(first_bullet==dead_bullet)
      {
        first_bullet=this_bullet;
        if(this_bullet!=NULL)
        {
          this_bullet->previous=NULL;
        }
      }
      else
      {
        dead_bullet->previous->next=this_bullet;
        if(this_bullet!=NULL)
        {
          this_bullet->previous=dead_bullet->previous;
        }
      }
      if(current_bullet==dead_bullet)
      {
        current_bullet=dead_bullet->previous;
      }
      delete dead_bullet;
    }
    else
    {
        for(int i=0;i<BULLETS;i++){
     if(bdraw == 1){
     Bullet.xadd(this_bullet->xvel);
     Bullet.yadd(0);
     Bullet.draw();
     if(Bullet.getx()<0 | Bullet.getx()>640){
     this_bullet->dead;
     bdraw=0;
     }
     }
     }
     this_bullet = this_bullet->next;
    }
}
}

void UpdateBullet()
{
  bullet* this_bullet=first_bullet;
  while(this_bullet!=NULL)
  {          
    this_bullet=this_bullet->next;
  }
  for (int i=0;i<BULLETS;i++){
  if(bdraw == 1){
  Bullet.updateBG();
  }
  }
}



I've gone through this over and over again and I think I just ended up complicating things by patching a bug here and there. Any help solving this problem would be greatly appreciated! (I think the bdraw=0 might be the reason my bullet animation freezes.... Ill check it out)

Share this post


Link to post
Share on other sites
Advertisement
Hey Caldiar,

I use a somewhat similar approach to handling short-life projectiles, and thought I might throw out a suggestion.

If I understand you right, you delete a projectile from the list once it becomes inactive (according to whatever rules, offscreen etc.), correct?
I had problems with this same thing for a while so I finally switched to an uglier method that works for me.

Instead of using one list, I made two, and a key variable to tell me which one was the active list. When a projectile needs to be added, it is added to the list which is currently active. If the number of projectiles in the list becomes larger than some arbitrary number ( a max limit if you will), then the active list variable is switched and the previously inactive list is completely emptied and the projectile gets inserted into this list (I base insertion off of Y value for 2D rendering purposes).
The main difference is that a projectile is never deleted individually, just made inactive, which therefore prevents it from being updated or rendered anymore.
But, all of the projectiles in the inactive list are still updated and rendered as normal, until they become inactive or the inactive list is emptied in preparation for becoming the active list.
Like I said this approach is ugly, but I was going crazy.
Hopefully this made some kind of sense and I am willing to send you the source if you want to see it/are brave enough to decipher it.

Coby

Share this post


Link to post
Share on other sites
that sounds interesting. So you have something like:
List A - Bullet 1, Bullet 2 - ACTIVE
List B - Empty - INACTIVE

List A has a max capacity of 2 bullets.
Bullet is added

List A = List B

List A - Bullet 1, Bullet 2 -INACTIVE
List B - Bullet 3 - ACTIVE

Add 2 Bullets

List A is emptied of all bullets.

List A - Bullet 5 - ACTIVE
List B - Bullet 3, Bullet 4 - INACTIVE

If this is the case and say you shoot 5 bullets in a short amount of time would two bullets suddenly disappear when they're cleared from the original list?

I would be extremely interested in seeing the source code =) my email is caldiar (at) eqguild (dot) net

Thanks for the reply =)

Share this post


Link to post
Share on other sites
Yep, that is the idea. To avoid the situation you mentioned, you just have to set the limit to a number that is slightly higher than roughly half of the maximum amount of projectiles that can be on screen, but is reasonable enough so that it doesn't eat up a lot of memory. For my RPG, there are never more than 50-70 projectiles on the screen at one time, so I set the arbitray limit for each list to 50 to make sure there will never be projectiles that suddenly vanish. This also makes sure that there will only be a maximum of 100 projectiles in memory at any given time.

I'll send the source now.
EDIT: I'll just post it here.


bool Game::AddNewSpell(CPoint* p,int x,int y,int typ,int flag)
{
CUtil u;
bool valid;

if(SpellArrayKey==1) //If First List is Active
{
if(CurrentSpellSlot<=50) //If Capacity has not been reached
{
valid=Spells1[CurrentSpellSlot].SetSpell(typ,x,y,p,flag); //Addition Successful
CurrentSpellSlot++;
}
else //Capacity has been reached
{
Spells2.DecrementDimen(50); //Empty the Second List
Spells2.IncrementDimen(50); //Re-establish Maximum Allocation for Second List
for(int az=1;az<=50;az++)
Spells2[az].SetGamePointer(this); //Re-establish Game pointers
SpellArrayKey=2; //Second List is now Active
CurrentSpellSlot=1; //One Spell in Second List
valid=Spells2[CurrentSpellSlot].SetSpell(typ,x,y,p,flag); //Addition Successful
CurrentSpellSlot++;
}
}
else if(SpellArrayKey==2) //If Second List is Active
{
if(CurrentSpellSlot<=50) //If Capacity has not been reached
{
valid=Spells2[CurrentSpellSlot].SetSpell(typ,x,y,p,flag); //Addition Successful
CurrentSpellSlot++;
}
else //Capacity has been reached
{
Spells1.DecrementDimen(50); //Empty the First list
Spells1.IncrementDimen(50); //Re-establish Maximum Allocation for First list
for(int azl=1;azl<=50;azl++)
Spells1[azl].SetGamePointer(this); //Re-establish Game Pointers
SpellArrayKey=1; //First List is now Active
CurrentSpellSlot=1; //One Spell in First List
valid=Spells1[CurrentSpellSlot].SetSpell(typ,x,y,p,flag); //Addition Successful
CurrentSpellSlot++;
}
}
else
u.ProcessTerminalError("Game::AddSpell-Invalid SpellArrayKey!!"); //Error catch
return valid;
}

Share this post


Link to post
Share on other sites
if((Bullet.getx()<0) || (Bullet.getx()>640)){
Bullet->dead = true;
}


| and & do bitwise calculations on ints. || is what you want in this case. And you need to assign to dead!

Share this post


Link to post
Share on other sites
Shadow - Thank you very much for the source code. Ill take a look at it right now!

Bob - I thought the | operator meant "or"? Ill have to look that one up hehe =)
Well, I tried it out anyways and I get a new access violation =) I smell progress.
Oh. the bullet->dead doesn't work for my code because bullet is referring to a class while this_bullet is the node in the linked list referring to a struct that initilizes a bullet based on the class settings. That might have come out a bit confusing hehe.

Thanks a bunch for all the help guys! =)

Share this post


Link to post
Share on other sites
Oh, yeah, Bullets is a Sprite not a Bullet. Damn, that's confusing. Well, you need to find the Bullet object corresponding to Bullets and set its dead to true, otherwise it won't get removed by Update. I think this_bullet->dead = true will do the trick, actually, looking at the context of that code.

| is bitwise or, i.e. 4 | 3 is 7, 6 | 2 is 6 ... it sets all bits in the answer that are in one of the arguments. || is logical or, which is almost always what you want in if tests.

Share this post


Link to post
Share on other sites
hmm well, this_bullet->dead = true does this:
Something like a Memory Access Violation at this line of code:
this_bullet=this_bullet->next;
in the Update Bullet function.

EDIT: Ah, its an Access Violation (Segmentation Fault)

Share this post


Link to post
Share on other sites
ok moved the this_Bullet=this_bullet->next; to the spot where it really belonged and I received my original error that I was trying to get back again.


bullet* NewBullet()
{
for(int i=0;i<BULLETS;i++){
if(bdraw == 0){
if(first_bullet==NULL)
{
first_bullet=new bullet;
current_bullet=first_bullet;
current_bullet->direction = face_right;
current_bullet->x = mario.getx();
current_bullet->y = mario.gety();
current_bullet->xvel = Bullet.getSpeed() * current_bullet->direction;
Bullet.set(current_bullet->x += 1, current_bullet->y += 0);
current_bullet->next=NULL;
current_bullet->previous=NULL;
}

else
{
current_bullet->next=new bullet;
current_bullet->next->direction = face_right;
current_bullet->next->x = mario.getx();
current_bullet->next->y = mario.gety();
current_bullet->next->xvel = Bullet.getSpeed() * current_bullet->next->direction;
current_bullet->next->previous=current_bullet->next;
current_bullet=current_bullet->next;
Bullet.set(current_bullet->x+=1, current_bullet->y+=0);
current_bullet->next=NULL;
}
bdraw = 1;
}
}
current_bullet->dead=false; ----THIS IS THE AFFECTED LINE
return current_bullet;
}



Access Violation (Segmentation Fault) and current_bullet->dead=false; is highlighted.

Im thinking since this_bullet is originally the first bullet then moves on until its at the current bullet Im actually setting current_bullet-> dead to true AND false at the same time? I wonder if that really is the problem...

Share this post


Link to post
Share on other sites
Okay, well I suspect that your bullet creation code is borked, not the killing code, in that case. What exactly are you trying to do? ... fill out the first unused bullet in the array? If so you ought to break out of your for loop when you've done one (i.e. inside the if(draw == 1) section).

It also strikes me that you are duplicating about 10 lines of code near the top of that function, and that smells of a refactoring opportunity:
bullet* NewBullet()
{
// Save the previous 'current bullet' so we can
// link the new one to it
bullet* last_bullet = current_bullet;
// Depending on your sorting techniques etc, this
// might not be necessary
while(last_bullet->next == NULL) last_bullet = last_bullet->next;

for(int i=0;i<BULLETS;i++){
if(bdraw == 0){
if(first_bullet==NULL)
{
first_bullet=new bullet;
current_bullet=first_bullet;
MakeBullet(current_bullet, NULL, NULL, i);
}

else
{
current_bullet->next=new bullet;
MakeBullet(current_bullet->next, current_bullet, NULL, i);
}
bdraw = 1;
break; // made one now, so don't do any more
}
}
current_bullet->dead=false; ----THIS IS THE AFFECTED LINE
last_bullet->next = current_bullet; // link to the rest of the list
return current_bullet;
}

void MakeBullet(Bullet* target, Bullet prev, Bullet next, int index){
// New function to fill out a bullet
// NB syntax may be wrong, I don't write C++ code
target->direction = face_right;
target->x = mario.getx();
target->y = mario.gety();
target->xvel = Bullet[index].getSpeed() * target->direction;
Bullet[index].set(target->x += 1, target->y += 0);
target->next=prev;
target->previous=next;
}


You're also mixing things up by storing some of your data in the linked list of Bullet structs, and some in a fixed array of Sprites. I think you need to pick one of those two and stick with it. At the minute the array is limiting the number of Bullets you can have, so why bother with the linked list?

You also had a bug in the second part of the creation code where you set the prev pointer of the new bullet to itself, and you don't link in the new bullet at all. I've added that functionality in.

Share this post


Link to post
Share on other sites
well.. didn't think about the break but that makes sense now. I tried that and I have a new bug.

Shoot one bullet. It hits end screen. I can shoot a new bullet. Shoot new bullet in opposite direction and the original bullet comes back in the same direction as new bullet.

Shoot another bullet. All bullets stop. Shoot another bullet in any direction and ALL bullets follow that direction.

Odd stuff. But i like that I have some progress and the game doesn't crash now lol =)

Share this post


Link to post
Share on other sites
well alright here's the deal.

The Sprite class handles initiating the image used to represent the object. It controls size, speed, movement units etc... that kind of thing.

The Bullet Struct handles creating multiple instances of the one bullet sprite instance and assigning damage, life, and individual direction of travel.

The linked list is what is keeping track of what bullet is which and if its active or not. It's easier to use a linked list for my multiple bullets since I can easily detatch from one bullet and start working with a new one by saying this_bullet = this_bullet->next
and delete the old bullet by going this_bullet->previous->dead = true;

however... deleting a bullet isn't actually working at the moment......

Share this post


Link to post
Share on other sites
WOOT!

Guess what? I now have working bullets! =D
Only 20 can be shot at a time. Tested. That works.
Bullets delete when off-screen. Tested. That works.
Bullets are free to be reshot after being deleted. Tested. Works.

One problem that shouldn't be too hard to fix - one way bullet. Only moves right not left. Ill just grab the players facing direction when firing the bullet to determine which direction it moves in.

Again, WOOT!

Share this post


Link to post
Share on other sites
I put together a pretty interesting particle system in C# known as SdlDotNet.Particles. Although you won't be able to use it (you're using C++), you can apply the concepts introduced in the system. It's built using particles, emitters, and manipulators. The emitters shoot out particles and the manipulators change the particles somehow. It's a very nice system to use and you could easily implement the concepts presented in it into your system.

Share this post


Link to post
Share on other sites
Thank you very much! =)

This looks very interesting and Ill be taking a closer look at it when I get back home and have some more time on my hands.

Currently the bullets work I just need to add some collision detection which wont be too hard to do. Once I get a working demo ready for people to download Ill start focusing on optimizing the code.

Thanks again!

~Caldiar~

Share this post


Link to post
Share on other sites
Gotta be kidding me.....

got bullets working right but I have an extremely weird bug that I can't pinpoit in the code... the players now move up and down rather than left and right. Bullets move up and down rather than left and right. It's almost as if... the x value of the movement is being swapped with the y value so any changes to x is actually affecting y. This makes no sense however since the bullet code I added can be seen here:


void NewBullet()
{
for(int i=0;i<BULLETS;i++){
if(bdraw==0){
Bullet.set(mario.getx()+0, mario.gety()+0);
bdraw = 1;
if(face_right==1){
Bullet.bface_right = true;
}
else{
Bullet.bface_right = false;
}
return;
}
}
}

void RenderBullet()
{
for(int i=0;i<BULLETS;i++){
if(bdraw == 1){
Bullet.draw();
}
}
}

void UpdateBullet()
{
for (int i=0;i<BULLETS;i++){
if(bdraw == 1){
Bullet.updateBG();
}
}
}

for(int i=0;i<BULLETS;i++){
UpdateBullet();
if(bdraw == 1){
if(Bullet.bface_right == true){
Bullet.xadd(2);
}
if(Bullet.bface_right == false){
Bullet.xadd(-2);
}
if(Bullet.getx()>640){
bdraw = 0;
}
}
}

for (int i=0;i<BULLETS;i++){
Bullet.init(&bulletbase,screen);
Bullet.setSpeed(2.0);
}



note that the movement is just temporary to get a working demo out there.

Share this post


Link to post
Share on other sites
*sighs*

Well, finally fixed it. Don't know how really... just copied the clean source into the folder where the files being tested were held... worked fine.

No direction control now though =\ Ill try adding that and see if that damn bug pops its ugly head up. If not Ill move on to collision detection and then A DEMO! whoohoo!

Share this post


Link to post
Share on other sites
seems I've found the problem.

Here's the code I added that came up with the same exact bug.


bool b_dir;

if(face_right == 1){
bullets.b_dir = true;
}
else{
bullets.b_dir = false;
}

.......

if(bullets.b_dir == true){
bullets.xadd(2)
}
else{
bullets.xadd(-2)
}




yep. that's it. I have no idea why it's doing what its doing but I know that if I remove that code its fixed. So Im removing that chunk of code. =P

EDIT: um... oddly the problem still stands even after removing the code that spawned the bug. what the hell.....

[Edited by - caldiar on May 12, 2006 12:30:02 AM]

Share this post


Link to post
Share on other sites
Bullets work great.

Added collision detection just now and decided to just make a new bullet when a bullet hit player 2. Works great. I shot 20 bullets at the character then turned around to see those same bullets suddenly pop up from player 1 as if they were being shot again into the opposite direction. I got a kick out of that =)

Just need to add life to player 1 and 2 and give player 2 a fire function and Ill have a small working demo ready for download! I'm so close I can smell it. No... wait... that's the coffee Im brewing.

Share this post


Link to post
Share on other sites
and an alpha demo is released! Read about it here
http://www.gamedev.net/community/forums/topic.asp?topic_id=392730

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By 3dmodelerguy
      So I am building a turn based rogue-like (think CDDA). The game is going to have a very large map (up to 1000's x 1000's) however to alleviate most of that I obviously can't render everything so there will just be render a certain radius around the player and just load in and out data as the player moves.
      The next major system I am prototyping is making interactive tiles destructible and pretty much everything will be destructible besides basic landscape (cars, doors, windows, structures, etc. will be destructible)
      While I am only rendering a certain amount of tiles around the player, I want to keep the amount of colliders active at one time to be as small as possible for performance and currently the tilemap tool I use automatically merges colliders together.
      So instead of creating a separate colliders for each of these tiles and having the destructible behavior tied to that object (which my tilemap tool would allow me to do) I was thinking that I would store an array of all the X and Y locations for the interactive tilemap layer and let the tilemap manage the colliders. 
      Then when I hit a collider on the interactive tilemap layer, instead of of getting the behavior for how to deal with the destruction for that tile from that game object, I would pull it from the array I mentioned earlier based on the tile I attempt to interact with which I already have.
      Does this sound like a good approach? Any other recommendations would be welcomed.
    • By NDraskovic
      Hey guys,
      I have a really weird problem. I'm trying to get some data from a REST service. I'm using the following code:
       
      private void GetTheScores() { UnityWebRequest GetCommand = UnityWebRequest.Get(url); UnityWebRequestAsyncOperation operation = GetCommand.SendWebRequest(); if (!operation.webRequest.isNetworkError) { ResultsContainer rez = JsonUtility.FromJson<ResultsContainer>(operation.webRequest.downloadHandler.text); Debug.Log("Text: " + operation.webRequest.downloadHandler.text); } } The problem is that when I'm in Unity's editor, the request doesn't return anything (operation.webRequest.downloadHandler.text is empty, the Debug.Log command just prints "Text: "), but when I enter the debug mode and insert a breakpoint on that line, then it returns the text properly. Does anyone have an idea why is this happening?
      The real problem I'm trying to solve is that when I receive the text, I can't get the data from the JSON. The markup is really simple:
      [{"id":1,"name":"Player1"},{"id":2,"name":"Player2"}] and I have an object that should accept that data:
      [System.Serializable] public class ResultScript { public int id; public string name; } There is also a class that should accept the array of these objects (which the JSON is returning):
      [System.Serializable] public class ResultsContainer { public ResultScript[] results; } But when I run the code (in the debug mode, to get any result) I get an error: ArgumentException: JSON must represent an object type. I've googled it but none of the proposed solutions work for me.
      Also (regardless if I'm in the debug mode or not) when I try to do some string operations like removing or adding characters to the GET result, the functions return an empty string as a result
      Can you help me with any of these problems?
      Thank you
    • By nihitori
      The Emotional Music Vol. I pack focuses on beautiful and esoteric orchestral music, capable of creating truly emotive and intimate moods. It features detailed chamber strings, cello and piano as the main instruments, resulting in a subtle and elegant sound never before heard in video game royalty-free music assets.

      The pack includes 5 original tracks, as well as a total of 47 loops based on these tracks (long loops for simple use and short loops for custom / complex music layering).

      Unity Asset Store link: https://www.assetstore.unity3d.com/en/#!/content/107032
      Unreal Engine Marketplace link: https://www.unrealengine.com/marketplace/emotional-music-vol-i

      A 15 seconds preview of each main track is available on Soundcloud:
       
    • By RoKabium Games
      Another one of our new UI for #screenshotsaturday. This is the inventory screen for showing what animal fossils you have collected so far. #gamedev #indiedev #sama
    • By eldwin11929
      We're looking for programmers for our project.
      Our project is being made in Unity
      Requirements:
      -Skills in Unity
      -C#
      -Javascript
      -Node.js
      We're looking for programmers who can perform a variety of functions on our project.
      Project is a top-down hack-and-slash pvp dungeon-crawler like game. Game is entirely multiplayer based, using randomized dungeons, and a unique combat system with emphasis on gameplay.
      We have a GDD to work off of, and a Lead Programmer you would work under.
      Assignments may include:
      -Creating new scripts of varying degrees specific to the project (mostly server-side, but sometimes client-side)
      -Assembling already created monsters/characters with existing or non-existing code.
      -Creating VFX
      -Assembling already created environment models
      If interested, please contact: eldwin11929@yahoo.com
      This project is unpaid, but with royalties.
       
      ---
      Additional Project Info:
      Summary:
      Bassetune Reapers is a Player-verus-Player, competitive dungeon crawler. This basically takes on aspects of dungeon crawling, but with a more aggressive setting. Players will have the option to play as the "dungeon-crawlers" (called the 'Knights', or "Knight Class", in-game) or as the "dungeon" itself (literally called the 'Bosses', or "Boss Class", in-game). What this means is that players can choose to play as the people invading the dungeon, or as the dungeon-holders themselves.
      Key Features:
      -Intense, fast-paced combat
      -Multiple skills, weapons, and ways to play the game
      -Tons of different Bosses, Minibosses, creatures and traps to utilize throughout the dungeon
      -Multiple unique environments
      -Interesting, detailed lore behind both the game and world
      -Intricate RPG system
      -Ladder and ranking system
      -Lots of customization for both classes s of customization for both classes
  • Advertisement