Pygame RPG Tutorial – Item Drops

This is Item Drops Tutorial (17) in the pygame RPG series

We have successfully created a very basic RPG environment, complete with enemies, stage clear prompts, status bar etc. One very “RPG-ish” thing we’re missing however, is Item drops.

Item drops is a really great feature due to the flexibility and wide range of features it can bring. Ranging from health recoveries, power-ups, special abilities and money, Item drops can bring a spark of life into what otherwise may be a dull and boring RPG.

In this tutorial, we’ll be working on adding “Health” and “Money” Item drops into our Pygame RPG. Furthermore, by the end of this tutorial, we’ll have created a framework, allowing you to add any number of Items into the game.


Item Class

Pygame RPG Coin Item Drop
The Coin drop

The first step is to begin creating an Item class. One thing we can take advantage of, is the re-usability that classes offer. Instead of creating separate classes for each Item drop that we make, we’ll just one class. Of course, we’ll have to be a bit smart about it how create the functions and parameters to allow for such a possibility.

RPG Health Item Drop
Heart Drop

For the first time, we’re including an extra parameter in the init function. These parameter will be used to determine the item number that we’re created. As you can see below, the image we load into the created Item, varies on the value of the itemtype parameter.

class Item(pygame.sprite.Sprite):
      def __init__(self, itemtype):
            super().__init__()
            if itemtype == 1: self.image = pygame.image.load("heart.png")
            elif itemtype == 2: self.image = pygame.image.load("coin.png")
            self.rect = self.image.get_rect()
            self.type = itemtype
            self.posx = 0
            self.posy = 0

For future use in other functions of the Item class, we’re also going to save itemtype into a variable called self.type.

In the Item.render() function, we’re going to update the values of rect of the Item with the position variables, and then blit (draw) it to the screen.

      def render(self):
            self.rect.x = self.posx
            self.rect.y = self.posy
            displaysurface.blit(self.image, self.rect)

We haven’t actually assigned the position variables any value here (besides the default of 0). This part will make more sense later when we actually work on the Enemy class, where the Item will be generated.

Goals

Before we proceed any further, let’s quickly review what these Items are going to do. The Health Item is meant to be a restorative item that heals you by one “heart”, as long as you aren’t at full health.

The Money item is obviously meant to be our currency in this game, obtained from beating enemies. We haven’t added an actual Money system yet, where we can purchase or sell things, but this serves as the base foundation.

We’ve assigned the Health and Money items, the itemtypes of “1” and “2” respectively.

Back to the actual coding part now.

The update() function is the part of the code responsible for checking whether the Player has “collected” the item or not. We determine that the Player has “collected” the item if he comes into contact with it. Which is a pretty standard way in many RPGs.

      def update(self):
            hits = pygame.sprite.spritecollide(self, Playergroup, False)
            # Code to be activated if item comes in contact with player
            if hits:
                  if player.health < 5 and self.type == 1:
                        player.health += 1
                        health.image = health_ani[player.health]
                        self.kill()
                  if self.type == 2:
                        # handler.money += 1
                        self.kill()

If the collision is detected, we then once again split into various blocks. The block that runs will be determined by the itemtype. In the above example, if the itemtype is 1, the health will be increased by 1.

We currently don’t have anything except a commented out piece of code in the second block, which would run if it was a money item. This is something we’ll develop further if we ever create a proper money system.


Enemy Class

We now have to decide where we want the item generation code to be. The place that makes the most sense to me, is in the enemy class. Or more specifically, in the function where the kill code is stored.

The reason behind this being, Item drops are typically found when enemies are killed. So it makes sense to generate the item here.

Randomized Chance

One problem however, is that Items are typically generated with a randomized chance (e.g: 10% chance). In order to fully implement the concept of Items, we need to come up with a way to determine with a new technique. Luckily, the numpy library can help us here with it’s random.uniform() function.

rand_num = numpy.random.uniform(0, 100)

The above line will generate numbers from 0 to 100. The unique feature about random.uniform, is that it has a uniform spread. If we run the above line 1000 times, each number from 0 – 100 will repeat about 10 times. Unlike a regular random function where there would be an uneven spread (in most scenarios)

So how does this help us in adding Item drops into our Pygame RPG? Look at the below code, belonging to the enemy update() function.

            # Activates upon either of the two expressions being true
            if hits and player.attacking == True or f_hits:
                  self.kill()
                  
                  if player.mana < 100: player.mana += self.mana # Release mana
                  player.experiance += 1   # Release expeiriance
                  
                  rand_num = numpy.random.uniform(0, 100)
                  item_no = 0
                  if rand_num >= 0 and rand_num <= 5:  # 1 / 20 chance for an item (health) drop
                        item_no = 1
                  elif rand_num > 5 and rand_num <= 15:
                        item_no = 2

We allocated the number 0 – 5 for Item1, and 6 – 15 for Item2. In other words, there is a 6% chance of a Health item dropping, and a 10% chance of a Coin dropping.

It may look unorthodox, but this is really one of the only ways to do it. Asking a computer, which runs off logic, to come up with a random value is not that simple.

We still aren’t done yet though! The below block of code comes right after the previous one, in the same function. We still have to add the Item into the Items group, and set it’s location.

First, we pass the item_no into the Item class, which creates the appropriate item.

                  if item_no != 0:
                        # Add Item to Items group
                        item = Item(item_no)
                        Items.add(item)
                        # Sets the item location to the location of the killed enemy
                        item.posx = self.pos.x
                        item.posy = self.pos.y

The last two lines of the above code, set the position of the item, to that of the enemy. This way the item appears in the exact location where the enemy was killed.


Game Loop

To make thing easier on us, we’re going to make a Items class where store all our items. We’ve already shown you multiple times in the above code, how and where to add the Item into the Items group.

Items = pygame.sprite.Group()

(You have to create the Items group outside the game loop!)

The benefit of this class is, that it allows us to iterate over all the items in it and call the same function on them.

    for i in Items:
          i.render()
          i.update()

Showcase

(We increased the item drop chance for the purpose of this video)


Next Section

The next tutorial is going to be quite interesting and full of new concepts. We’ll be adding buttons, a new cursor, and the ability to pause and resume your game at will.


This marks the end of the Pygame RPG – Item Drops tutorial. Any suggestions or contributions for CodersLegacy are more than welcome. Questions about the tutorial content can be asked in the comments section below.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments