Here is my report on my review on three different types cloud software applications that I have used.
Report
Beginners Guide to creating a Pygame
Monday, 27 November 2017
The final steps!
Before we get on to talking about how to add in different sound effects, I taught it would be best to make a video on what my code actually looks like. I know it can be confusing when you are going by a written blog so I hope this video helps you to know where to put everything๐
The only thing left to do is add in the music! This is easy to do and does not involve adding it a lot of lines of code. Before you start coding, you need to download all the music files that you want to add into the game. I decided to add in a score sound for when the score increases and a sound for when the game is over. I did not add in a background sound to run during when the game because I felt it was too much music but if you wanted to do it, it is done the exact same way as how i will be showing you to do the rest. You just have to search about for the one you are looking for but make sure you get them for free and don't have to sign up for an account to download anything. I'll leave the links below to the ones that I am using.
To add in the both the score and game over sound you only need to lines of code which are pygame.mixer.music.load('filename here')and pygame.mixer.music.play(0, 0.0). These lines of code load the music file into the game and then play it. For the score these lines of code need to be added in, in the else part of the if statement for the collision detection. For the game over sound, this code needs to be added in where you are terminating the game just above where you update it.
After that, it should all be working!
That is the game all finished! Hope it all worked out for you and my explaining of things was not too difficult.
Score sound - http://www.orangefreesounds.com/button-beep-tone/
Game over sound - http://www.orangefreesounds.com/funny-game-sound/
The only thing left to do is add in the music! This is easy to do and does not involve adding it a lot of lines of code. Before you start coding, you need to download all the music files that you want to add into the game. I decided to add in a score sound for when the score increases and a sound for when the game is over. I did not add in a background sound to run during when the game because I felt it was too much music but if you wanted to do it, it is done the exact same way as how i will be showing you to do the rest. You just have to search about for the one you are looking for but make sure you get them for free and don't have to sign up for an account to download anything. I'll leave the links below to the ones that I am using.
To add in the both the score and game over sound you only need to lines of code which are pygame.mixer.music.load('filename here')and pygame.mixer.music.play(0, 0.0). These lines of code load the music file into the game and then play it. For the score these lines of code need to be added in, in the else part of the if statement for the collision detection. For the game over sound, this code needs to be added in where you are terminating the game just above where you update it.
After that, it should all be working!
That is the game all finished! Hope it all worked out for you and my explaining of things was not too difficult.
Score sound - http://www.orangefreesounds.com/button-beep-tone/
Game over sound - http://www.orangefreesounds.com/funny-game-sound/
Wednesday, 22 November 2017
Adding a start screen & a Game Over screen!
We are nearly done with completing the game fully! The one few things left are adding music and the start and finish screens.
In this blog, I will start of with how you add an opening screen to the game and to start the game once the player hits any key.
The first thing we need to add is two functions. One called waitForPlayerToPressKey and the other drawText. The waitForPlayerToPressKey function must include a while loop that is set to True so it always runs. In this while loop, is a for loop. This for loop is the same for loop as the one we used when setting up the game loop. Then, two if statements are needed, one for if the player decides to quit the game instead of playing it which is just calling the terminate function. The second if statement is the event.type == KEYDOWN, which means if any key is pressed. This just needs to be returned.
The second function drawText will pass in the text, font, surface, x and y. You need to create a new object so you can call the render method. I called my object textobj and passed in text, True and the colour. Next, you need to know the size and location of the Surface object. You can get a Rect object with this information from the get_rect Surface method. The Rect object returned from get_rect has a copy of the width and height information from the Surface object which is saved in textRect. We then need to change the location of the textRect by setting a new value for its top-left attribute. At the end you just blit the text onto the screen by passing in textobj and textrect as the parameters.
Once this is done these two functions are all good to use!
So, when setting up the start screen, we called the drawText method for each line of text we want to add in passing in the text we want displayed, the font variable that we set up in a previous blog, windowSurface and the the x and y position we want to set the top left of the text to. Then we need to update the game and call the waitForPlayerToPressKey function.
The same principles apply for creating the screen when the game is over. Only this time the code is added in down the bottom where you are terminating the game.
Tuesday, 21 November 2017
Terminating the game!
As we have to game up and running we now need to add in a few extra pieces to complete the game. These things included the game finishing when the player reaches a certain score or is not quick enough to move the paddle and bounce the ball back up, add music into the game and allow the user to mute it if they wish to not have it playing and also add a start screen and a finishing screen showing their score.
In this post I will show you how to terminate the game. For this we need to make a function that will call the methods used to end a pygame. Functions are usually at the top of the program just below the declared variables. I have called mine terminate for convenience. In this function you should add in two lines of code. One is to call the quit method from the pygame class. The second line of code is calling the exit method from the sys class. The quit method stops the game from running and the exit method closes down the game.
This function is then used at the very end of the while loop just above where you redraw the paddle and the block. I decided that when the score is 10 or the block passes by the players paddle, the game should end. However, you can decide on a different score if you want.
So, you check this with an if statement and if true, call the terminate function.
That's it on how to terminate the game! in the next blog I will show you how to add in a start screen and for the game to start once the player presses any key and a finish screen showing the score.
Saturday, 18 November 2017
Collision Detection and adding in the Score!
In this post, we will work on collision detection. This means that we need to figure out a way for game to know when the block collides with the players paddle and in turn, bounce the ball back up and increment their score.
First we need to add the line of code in of initialising score to 0. You can place this just underneath the setting up of the player's paddle.
Near the end of the while loop, below windowSurface.fill(WHITE), this is where you add in the collision detection. This is done with one nested if statement. This is done by calling the colliderect on the player object passing the block object in as the argument. If there is an overlap between player and block the method returns True.
Once in this if statement, you need to find out if moveUp is set to true and if so, set it to false and moveDown to true. Then add the MOVESPEED to the block.bottom. Else, set moveUp to true and moveDown to false and subtract the MOVESPEED from the block.bottom. This means that when the block collides with the paddle the block will bounce back up the window. Also, add 1 point to the score. You can increment the score by whatever number to want but for this blog I am going to keep it simple and leave it at one point.
Before adding the score to the screen, we need to assign a variable to the font type. You can add this in up the top where you have set up the pygame. We use the pygame.font.SysFont method and we want to set the first parameter to none so we get the default font and then the second parameter to the size we want the font to be. Around 48 should do perfectly.
To add the score to the screen, it is a simple line of code using the drawText method. The first parameter is the text you want shown, the second is the type of font which we saved in a variable called font, the third is the variable windowSurface so that it knows where to draw it. Then the fourth and fifth ones are where you want to place it on the screen with the x and y position.
Near the end of the while loop, below windowSurface.fill(WHITE), this is where you add in the collision detection. This is done with one nested if statement. This is done by calling the colliderect on the player object passing the block object in as the argument. If there is an overlap between player and block the method returns True.
Once in this if statement, you need to find out if moveUp is set to true and if so, set it to false and moveDown to true. Then add the MOVESPEED to the block.bottom. Else, set moveUp to true and moveDown to false and subtract the MOVESPEED from the block.bottom. This means that when the block collides with the paddle the block will bounce back up the window. Also, add 1 point to the score. You can increment the score by whatever number to want but for this blog I am going to keep it simple and leave it at one point.
Before adding the score to the screen, we need to assign a variable to the font type. You can add this in up the top where you have set up the pygame. We use the pygame.font.SysFont method and we want to set the first parameter to none so we get the default font and then the second parameter to the size we want the font to be. Around 48 should do perfectly.
To add the score to the screen, it is a simple line of code using the drawText method. The first parameter is the text you want shown, the second is the type of font which we saved in a variable called font, the third is the variable windowSurface so that it knows where to draw it. Then the fourth and fifth ones are where you want to place it on the screen with the x and y position.
Tuesday, 14 November 2017
Making the ball move!
In this post I will be helping you the get to block to move automatically once the game is loaded. There will be no user input needed for this. It will bounce about on its own.
For this we will need four separate if statements with a nested if/else in each one. These if statements look very familiar. The only thing different is what side of the block you are changing in order for it to move and the speed you are setting it to.
For the moveDown if statement, you need to do the nested if/else statement to find out if the block.bottom >= WINDOWHEIGHT. If it is greater than the height of the window, then you need to subtract the MOVESPEED_V from block.bottom. After this the moveDown has to be changed to False and moveUp has to be changed to True. In the else, you just add the MOVESPEED_V to the block.bottom.
When writing the code for the block.right side, you need to check it against the WINDOWWIDTH and subtract the MOVESPEED_H to the block.right or else, add it. This code will detect if the block has hit the right side of the window and if so, bounce of it in the opposite direction.You then set the moveRight to False and the moveLeft to True.
However when checking the block.left and the block.top, they need to be checked if they are <= 0 because the top of the screen and the left of the screen both are 0. The MOVESPEED_H is added to the block.left, else, subtracted and the moveLeft is set to False and moveRight is set to True. When the block hits the left side of the window, it will also bounce in the opposite direction.
The MOVESPEED_V is added to the block.top, else also subtracted. block.top detects if the block has hit the top of the window and if so, bounce downwards. The block.top has to be set to False here and the block.down and to be set to True.
Tip: The integer you set the MOVESPEED_V and the MOVESPEED_H to at the top of the program is how fast the the block is going to move around the screen. MOVESPEED_V is the speed you want the ball to move when it is going in a vertical direction and MOVESPEED_H is the speed when it is going in a horizontal direction.
For this we will need four separate if statements with a nested if/else in each one. These if statements look very familiar. The only thing different is what side of the block you are changing in order for it to move and the speed you are setting it to.
For the moveDown if statement, you need to do the nested if/else statement to find out if the block.bottom >= WINDOWHEIGHT. If it is greater than the height of the window, then you need to subtract the MOVESPEED_V from block.bottom. After this the moveDown has to be changed to False and moveUp has to be changed to True. In the else, you just add the MOVESPEED_V to the block.bottom.
When writing the code for the block.right side, you need to check it against the WINDOWWIDTH and subtract the MOVESPEED_H to the block.right or else, add it. This code will detect if the block has hit the right side of the window and if so, bounce of it in the opposite direction.You then set the moveRight to False and the moveLeft to True.
However when checking the block.left and the block.top, they need to be checked if they are <= 0 because the top of the screen and the left of the screen both are 0. The MOVESPEED_H is added to the block.left, else, subtracted and the moveLeft is set to False and moveRight is set to True. When the block hits the left side of the window, it will also bounce in the opposite direction.
The MOVESPEED_V is added to the block.top, else also subtracted. block.top detects if the block has hit the top of the window and if so, bounce downwards. The block.top has to be set to False here and the block.down and to be set to True.
Tip: The integer you set the MOVESPEED_V and the MOVESPEED_H to at the top of the program is how fast the the block is going to move around the screen. MOVESPEED_V is the speed you want the ball to move when it is going in a vertical direction and MOVESPEED_H is the speed when it is going in a horizontal direction.
Monday, 13 November 2017
Adding the ball to the screen
Now that we have the paddle moving, we need to add the ball to the screen. An actual circle as a ball is more complicated to do because it can not be done like we made the paddle. It has to be done with many more steps and personally that is to complicated for this simple game so instead I have decided to use a square. If you wish to use a ball instead that is no problem and if so, feel free to leave a comment on how you done it so I could update my code. It is easy to find this code online.
Anyway, the block is done the same way as the paddle. The only thing different is that the size of the shape is smaller so that it can be turned into a square. This block will be moving randomly about the screen so first what we need to do is set up the x position and the y position of the block using the random.randint method. The x position needs to be set with a random number between 0 and the WINDOWWIDTH.
The y position needs to be set with a random number between 0 and 300. The reason why I have picked 300 instead of the WINDOWHEIGHT is because 300 is where the paddle is placed and we do not want it to start up with the block passed the paddle or the game would not work.
These are both saved into two variables. I called them xPos and yPos for convenience. Now that these are set, they can be used as the first two parameters when creating the block followed by the height and width you want the block to be. Make sure these are the same size so that you get a square.
Once this is done you then add it to the screen by using the pygame.draw.rect method and enter in the parameters windowSurface, BLACK and block. block is what I named this object as.
Don't forget to add in the extra line of code at the bottom of the loop, like we done when creating the paddle, so that it is added to the game!
Anyway, the block is done the same way as the paddle. The only thing different is that the size of the shape is smaller so that it can be turned into a square. This block will be moving randomly about the screen so first what we need to do is set up the x position and the y position of the block using the random.randint method. The x position needs to be set with a random number between 0 and the WINDOWWIDTH.
The y position needs to be set with a random number between 0 and 300. The reason why I have picked 300 instead of the WINDOWHEIGHT is because 300 is where the paddle is placed and we do not want it to start up with the block passed the paddle or the game would not work.
These are both saved into two variables. I called them xPos and yPos for convenience. Now that these are set, they can be used as the first two parameters when creating the block followed by the height and width you want the block to be. Make sure these are the same size so that you get a square.
Once this is done you then add it to the screen by using the pygame.draw.rect method and enter in the parameters windowSurface, BLACK and block. block is what I named this object as.
Don't forget to add in the extra line of code at the bottom of the loop, like we done when creating the paddle, so that it is added to the game!
Tuesday, 7 November 2017
Making the Paddle move!
In this post I am going to help you to get the paddle to move either left or right depending on the users input.
To begin, we need to use a while loop to enter the game and allow it to continue running until the user exits the game. We do this by setting the while loop to True. This way we will always be able to enter it. Once in the while loop, a For loop needs to be created to queue up all the events in the order they are going to run. This line of code that is used for this is for event in pygame.event.get(). Before we get the paddle to move we first need to create an if statement so that the game terminates when the user exits the game. This is done by checking if the event.type == QUIT. If true, you need to call the quit method from the pygame class to quit the game the user is currently playing and then call the exit method from the sys class to exit the open window.
To get the paddle to move, we now need to use nested if statements and the event.type and the event.key methods. When the event.type == KEYDOWN the pLeft and pRight variables need to be changed depending on whether the left key is pressed or the right key.
For example: if the left key is pressed, pLeft has to be set to True and pRight has to be set to False. It would be the opposite if the right key is pressed.
When the event.type == KEYUP, this means when the key pressed is released, the pLeft and pRight variables need to be set back to False so that they can be reset. For example: if event.type == K_LEFT, then pLeft == False. The same should be done for the right key. Do not worry if this is confusing for you, I will insert a screenshot of the solution at the end of this post.
To finish this off we need two if statements to make the paddle move. For the first if statement, you need to find out if pLeft is true and if the left side of the paddle is greater than 0. 0 is the edge of the left side of the window. This is checking whether or not the paddle has reached the left side of the window. If it has it will enter this if statement.
This is where we add the line of code that makes the paddle actually move. What you need to do is use the left side of the paddle and the MOVESPEED variable. You need to set player.left = player.left - MOVESPEED. This will change where the left side of the paddle is placed and in turn, allow us to move it.
Same goes for moving right. Although instead of checking player.left is greater than 0, you check if player.right < WINDOWWIDTH and if so, add the MOVESPEED to player.right.
At the end of the while loop you need to add in a few lines of code that will allow the game to run and also update any movements made while the game is running. First we need to fill in the background, I picked white. Then we need to draw the paddle onto the screen again but this time, it has moved and call the update method in the pygame class.
We also need to add in the time.sleep method and add in the amount of seconds as the parameter. This method pauses execution of your Python program.
Okay so that is how we move the paddle either left or right depending on the user's input. Now that we have one of the two main objects on the screen, it will not be too hard to finish this game!๐
Tip: Pyscripter does not use curly brackets when creating an if statement or any loops. It uses indentation. So when you want to write something after an if statement, you do 1 indent in and if it is nested, you continue to indent after each statement.
To begin, we need to use a while loop to enter the game and allow it to continue running until the user exits the game. We do this by setting the while loop to True. This way we will always be able to enter it. Once in the while loop, a For loop needs to be created to queue up all the events in the order they are going to run. This line of code that is used for this is for event in pygame.event.get(). Before we get the paddle to move we first need to create an if statement so that the game terminates when the user exits the game. This is done by checking if the event.type == QUIT. If true, you need to call the quit method from the pygame class to quit the game the user is currently playing and then call the exit method from the sys class to exit the open window.
To get the paddle to move, we now need to use nested if statements and the event.type and the event.key methods. When the event.type == KEYDOWN the pLeft and pRight variables need to be changed depending on whether the left key is pressed or the right key.
For example: if the left key is pressed, pLeft has to be set to True and pRight has to be set to False. It would be the opposite if the right key is pressed.
When the event.type == KEYUP, this means when the key pressed is released, the pLeft and pRight variables need to be set back to False so that they can be reset. For example: if event.type == K_LEFT, then pLeft == False. The same should be done for the right key. Do not worry if this is confusing for you, I will insert a screenshot of the solution at the end of this post.
To finish this off we need two if statements to make the paddle move. For the first if statement, you need to find out if pLeft is true and if the left side of the paddle is greater than 0. 0 is the edge of the left side of the window. This is checking whether or not the paddle has reached the left side of the window. If it has it will enter this if statement.
This is where we add the line of code that makes the paddle actually move. What you need to do is use the left side of the paddle and the MOVESPEED variable. You need to set player.left = player.left - MOVESPEED. This will change where the left side of the paddle is placed and in turn, allow us to move it.
Same goes for moving right. Although instead of checking player.left is greater than 0, you check if player.right < WINDOWWIDTH and if so, add the MOVESPEED to player.right.
At the end of the while loop you need to add in a few lines of code that will allow the game to run and also update any movements made while the game is running. First we need to fill in the background, I picked white. Then we need to draw the paddle onto the screen again but this time, it has moved and call the update method in the pygame class.
We also need to add in the time.sleep method and add in the amount of seconds as the parameter. This method pauses execution of your Python program.
Okay so that is how we move the paddle either left or right depending on the user's input. Now that we have one of the two main objects on the screen, it will not be too hard to finish this game!๐
Tip: Pyscripter does not use curly brackets when creating an if statement or any loops. It uses indentation. So when you want to write something after an if statement, you do 1 indent in and if it is nested, you continue to indent after each statement.
Monday, 6 November 2017
Creating the window & adding the paddle to the screen!
Since all the variables are written, it is now time to start creating the game.
Before we being creating the paddle we need to initialise pygame by making one call which is pygame.init(). This will attempt to initialise all the pygame modules for you that you will be using. Personally I like to put this code after all my functions because it works better to have your functions right underneath your variables. (We will be doing the functions in a later blog).
Before we started creating the paddle we need to set up the pygame window that the game will run in. This is done by using the pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)), these are the variables that we set up in the last post, and this should be saved in a variable called windowSurface. Next we are going to add a tittle to the top of the window. This is done by adding the line of code pygame.display.set_caption("GAME"). Where I have put the word "GAME" is where you can call it whatever you want.
Now that we have the window set up, we can begin creating the player's paddle. We can do this by calling the Rect method and saving this information in a variable called player. The parameters you put in this method relate to where you want to put it on the screen(x-axis and y-axis) and the length and width you want to set the paddle to. Once you have this done you need to add it to the window by adding in pygame.draw.rect(windowSurface, BLACK, player). This draws the player object onto the window in the colour that I have saved in the BLACK variable.
In the next blog post I will show you how to move the block using users' input.
Tip: To comment you code, use '#' before the sentence. This is ignored when the program is run and will not interfere with the compiling.
Before we being creating the paddle we need to initialise pygame by making one call which is pygame.init(). This will attempt to initialise all the pygame modules for you that you will be using. Personally I like to put this code after all my functions because it works better to have your functions right underneath your variables. (We will be doing the functions in a later blog).
Before we started creating the paddle we need to set up the pygame window that the game will run in. This is done by using the pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)), these are the variables that we set up in the last post, and this should be saved in a variable called windowSurface. Next we are going to add a tittle to the top of the window. This is done by adding the line of code pygame.display.set_caption("GAME"). Where I have put the word "GAME" is where you can call it whatever you want.
Now that we have the window set up, we can begin creating the player's paddle. We can do this by calling the Rect method and saving this information in a variable called player. The parameters you put in this method relate to where you want to put it on the screen(x-axis and y-axis) and the length and width you want to set the paddle to. Once you have this done you need to add it to the window by adding in pygame.draw.rect(windowSurface, BLACK, player). This draws the player object onto the window in the colour that I have saved in the BLACK variable.
In the next blog post I will show you how to move the block using users' input.
Saturday, 4 November 2017
Setting up the game!
The game I have decided to demonstrate in this blog is a simple one but it covers all areas of creating a pygame. It is a game with very little on the screen, only a paddle and a ball and a score, but it is a good way to start of learning how to code. The game is where a ball is moving around the screen and when it reaches near the bottom, you move the paddle over to hit it back up. I have this game already made but in each blog post, I am going to show you how to do it step by step.
So, to get this started we need to set the game up with all the variables that we will be using. I will go through why we need each one and then insert a screenshot of my code to help you along the way.
The first thing we need to do is import all the necessary libraries such as pygame, sys, random and time from the pygame.locals import*. If you do not have all of these then you will receive and error when trying to run.
Next, we set up the colours. BLACK is (0,0,0), WHITE is (255,255,255) and RED is (255,0,0). You can choose to change these colours by having a number between 0 and 255 in the order of how red, green and blue the shade is(RGB). You can find all the colours online. However, I decided to leave it simple.
We now need to set up the movement variables. You can name these anything you want but it works better if you name it something relatable to what you are using it for. With that in mind I named my boolean variables moveLeft, moveRight, moveUp and moveDown, setting moveLeft and moveUp to True and moveRight and moveDown to False. Also the variables for the paddle need to be set to false. I named them pLeft and pRight.
Other variables I have added in are MOVESPEED, WINDOWWIDTH, WINDOWHEIGHT, MOVESPEED_V and MOVESPEED_H. These are for the speed of the ball to go, the size I want the window to be and when the block hits either the window width or height to bounce back. You can set these to any integer you want but remember if you decide to use different ones than I am, make sure to do the same with any other numbers as well!๐
So, to get this started we need to set the game up with all the variables that we will be using. I will go through why we need each one and then insert a screenshot of my code to help you along the way.
The first thing we need to do is import all the necessary libraries such as pygame, sys, random and time from the pygame.locals import*. If you do not have all of these then you will receive and error when trying to run.
Next, we set up the colours. BLACK is (0,0,0), WHITE is (255,255,255) and RED is (255,0,0). You can choose to change these colours by having a number between 0 and 255 in the order of how red, green and blue the shade is(RGB). You can find all the colours online. However, I decided to leave it simple.
We now need to set up the movement variables. You can name these anything you want but it works better if you name it something relatable to what you are using it for. With that in mind I named my boolean variables moveLeft, moveRight, moveUp and moveDown, setting moveLeft and moveUp to True and moveRight and moveDown to False. Also the variables for the paddle need to be set to false. I named them pLeft and pRight.
Other variables I have added in are MOVESPEED, WINDOWWIDTH, WINDOWHEIGHT, MOVESPEED_V and MOVESPEED_H. These are for the speed of the ball to go, the size I want the window to be and when the block hits either the window width or height to bounce back. You can set these to any integer you want but remember if you decide to use different ones than I am, make sure to do the same with any other numbers as well!๐
Thursday, 2 November 2017
How to download Python, Pyscripter & Pygame
So to get started with creating a Pygame, what we need to do is download all the necessary files that we need to use to make sure that it runs smoothly for us. I taught there would be no better way to do this than by creating a screen-cast of how i downloaded everything and upload it. This way its going to be so much easier for you to follow each step.
Python link --> https://www.python.org/downloads/
Pyscripter link --> https://sourceforge.net/projects/pyscripter/?source=typ_redirect
Pygame link --> https://bitbucket.org/pygame/pygame/downloads/
Now when your going to download the Pygame file, I find it best to download the exact same one I did to guarantee that it works. When you scroll down through them look for the
pygame-1.9.2a0-hg_ea3b3bb8714a.win32-py2.7.msi
link. It's the one that i found worked and will defiantly work for you! Thank you in advance for watching my video and I hope it all downloads correctly for you too!๐
Saturday, 28 October 2017
What is this Blog about?
My name is Rachel McClelland and I am currently a second year student in Galway Mayo Institute of Technology studying Software Development.
In this blog I am going to show you how to create a user friendly game in Python using a program called Pyscripter.
I will demonstrate on how to download everything you need in order to get it up and running. I will also provide a basic step by step guide on everything you need to know about the game I am going to make! In the end I hope to have it working perfect and for it to allow the user to interact with the game in some way. I hope you find what you are looking for! ๐
In this blog I am going to show you how to create a user friendly game in Python using a program called Pyscripter.
I will demonstrate on how to download everything you need in order to get it up and running. I will also provide a basic step by step guide on everything you need to know about the game I am going to make! In the end I hope to have it working perfect and for it to allow the user to interact with the game in some way. I hope you find what you are looking for! ๐
Subscribe to:
Posts (Atom)