Fixing bullet trajectory

Hello Everyone!!!

I am relatively new to Processing as a whole and would like some assistance.
I am trying to make a spaceship game where when the player presses the w key it fires a bullet

Unfortunately, the bullet only fires once and starts its trajectory at y = 400.

How do I fix these problems? I would like code and an explanation on why it is doing this and how to fix a problem like this if it returns in the future.

Help is greatly appreciated!

class ship(object):
    def __init__ (self, xpos, ypos, speed):
        self.xpos = xpos
        self.ypos = ypos
        self.speed = speed
        
        
    def show(self):
        fill(0, 255, 0)
        noStroke()
        rect(self.xpos, self.ypos, 50, 50) 
    
        
class bullet(object):
    def __init__ (self, xpos, ypos, speed):
        self.xpos = xpos
        self.ypos = ypos
        self.speed = speed
        
    def show(self):
        fill(255, 0, 0)
        noStroke()
        rect(self.xpos + 22, self.ypos - 10, 10, 10)

    
def keyPressed():
    if(keyCode == UP):
        s.ypos -= s.speed
    if(keyCode == DOWN):
        s.ypos += s.speed
    if (keyCode == LEFT):
        s.xpos -= s.speed
    if (keyCode == RIGHT):
        s.xpos += s.speed
    return(s.xpos, s.ypos)
            

def keyReleased():
    if(keyCode == UP):
        s.ypos -= 0
    if(keyCode == DOWN):
        s.ypos += 0
    if(keyCode == LEFT):
        s.xpos -= 0
    if(keyCode == RIGHT):
        s.xpos += 0

def setup():
    size(800, 800)
    global s
    global b
    s = ship(200, 400, 20)
    b = bullet(s.xpos, s.ypos, 3)
    
def draw():
    background(0)
    s.show()
    if(key == 'w'):
            b.xpos = s.xpos
            bxpos -= b.speed
            b.show()
1 Like

You’ll need a list to hold multiple bullets (I’m assuming that you can fire more than one), which you then update on a per-frame basis. I’ve adapted the last bit of your code to make it work. Note that I also elected to use a keyPressed function.

...

def setup():
    size(800, 800)
    global s
    global bullets
    s = ship(200, 400, 20)
    bullets = []
    
def draw():
    background(0)
    s.show()

    for b in bullets:
        b.xpos -= b.speed
        b.show()

def keyPressed():
    if(key == 'w'):
        bullets.append( bullet(s.xpos, s.ypos, 3) )  

I’m not sure if the bullets are heading in the correct direction, but that shouldn’t be tricky to adjust.

Hope that helps!

3 Likes

Thank you so much!!! Stile helped a lot but I have a few more questions…

for b in bullets:
        b.xpos -= b.speed
        b.show()

What is the logic behind this block of code and why?

If I wanted to make a function that checks if the bullets collided with another object would I have to check every single bullet in the list for a collision in a for loop? How would I do this?

1 Like

Yes – you would use a loop for the collision detection as well. However, you can make use of the existing loop:

for b in bullets:
        b.xpos -= b.speed
        b.show()

        # insert code here to check 
        # if b has collided with an enemy

Regarding the logic of the for block – bullets is a list that holds every bullet you have ‘spawned’/fired. With each frame, the loop spins through the entire list, however long it may be, adding/subtracting speed to each item.

You will have to be quite comfortable combining loops and lists for your next proposed step (collisions). I’m not sure what type of collision detection you will be performing (AABB?), but I’m assuming that you want multiple enemies? This will involve comparing lists with other lists, as well as ‘pruning’ any dead enemies and expired bullets from your existing lists.

1 Like

Yes, I do want multiple enemies however the enemies will be created from a class.

So would I have to compare the bullets current x - value using an index with the enemies position?

The way I am thinking of doing collision is with the following code:

for i in range(len(bullets)):
        bullet = bullets[i]
        if(bullet.xpos == e.xpos and bullet.ypos == e.ypos):
            # I have yet to figure out what I want to do when the bullet collides
            # e.xpos and e.ypos is the enemies x and y posistions
            #Keep in mind that this code isn't supposed to work yet as I have yet to create the class of the enemies
1 Like

The collision detection is not that simple. You are supposing that the bullet’s x/y position (a single pixel’s coordinate) will be exactly equal to the enemy’s x/y position (another single pixel’s coordinate). In reality, these objects both have 2D areas that can overlap in various ways. Hence, you need to look into AABBs.

I would recommend that you focus on collision detection before creating a list of enemies, or even an enemy class. In other words, just draw some random rect to serve as the enemy for now. Then, see if you can detect bullet collisions against it.

If you’re stuck on this step, let me know and I can send a basic example.

1 Like

For introductions to basic collision detection in Processing (although written for Java mode, not processing.py, the principles are the same) – see these tutorials with examples:

1 Like

Hello again!!!

Thanks for all the help but I still have a question

Thanks to links sent by the other user I am developing a collision method which when the bullet hits a rectangle I want to make the rectangle disappear.

How do I do that and is their a built in function in processing to remove objects from the screen?

1 Like

Hello again!!!

Can you send me a basic example of bullet collision. I have been working on this for a while and now I am stuck

Sure. To use an adaption of what I provided in my previous responses:

...

def setup():
    size(800, 800)
    global s
    global bullets
    s = ship(200, 400, 20)
    bullets = []
    
def draw():
    background(0)
    s.show()
    
    enemyx = 10; enemyy = 385
    enemyw = 20; enemyh = 20
    rect(enemyx, enemyy, enemyw, enemyh)

    for b in bullets:
        b.xpos -= b.speed
        b.show()
        
        if (    b.xpos+10 >= enemyx and b.xpos <= enemyx+10
            and b.ypos+10 >= enemyy and b.ypos <= b.ypos+10
            ):
            print('HIT! on frame:' + str(frameCount))

def keyPressed():
    if(key == 'w'):
        bullets.append( bullet(s.xpos, s.ypos, 3) )

If this is working, you can convert the enemy to an object. Of course, this code is for a single enemy. You will need to adapt it for multiple targets (i.e. adding a list to manage multiple enemies, etc.)

Thank you so much!!!

I knew I was on the right track but I was stuck on how to move forward!!

You have made me into a better programmer and game programmer as I know how to solve these problems if I encounter them in the future.

Thank you!!

This is kinda of an off topic question but can we create multiple levels in a Processing Game. If so how do you do that

Yes you can.

You would need a variable levelCounter and a variable maxLevel

When a level is finished you increase levelCounter by 1

Depending on levelCounter you can use different speeds and different color in each level

Once levelCounter reaches maxLevel you are in a new situation / state where you display a screen that says you successfully finished the game … or you saved the world…

Chrisir

There are many ways, but using a level counter to control state as @Chrisir suggests is one of the simplest. You could also create level objects for a non-linear set of levels / stages that aren’t easily navigated by incrementing.

Here is a simple toy to help you understand some of the issues involved. One approach is to use your level counter to load dynamic data – for example, different background colors as an array levelColor[]. Another approach is to use it to decide between custom code – for example a platform level vs a puzzle level as a switch statement between level1() and level2() functions.You can parameterize one big shared “level” code with data, or break different levels out into separate functions, or do some of each. What is appropriate depends on your game design.

int level = 0;
int MAXLEVEL = 3;
color levelColor[];
void setup() {
  // set current level
  level = 0;
  // define an array of variables, one per level
  levelColor = new color[]{
    color(255), 
    color(128), 
    color(0)
  };
}
void draw() {
  background(levelColor[level]);
  fill(0, 255, 0);
  switch(level) { // draw the current level
  case 0: 
    level0(); 
    break;
  case 1: 
    level1(); 
    break;
  case 2: 
    level2(); 
    break;
  }
  fill(255, 0, 0);
  text("LEVEL " + level, 30, 50);
  text("press space", 17, 80);
}
void keyReleased() {
  level = (level+1)%MAXLEVEL; // go to next level
}
void level0() {
  ellipse(width/2, height/2, width/2, height/2);
}
void level1() {
  rect(10, 10, width-20, height-20);
}
void level2() {
  triangle(0, 0, width, height/2, 0, height);
}