<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Juan P. Romano - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Juan P. Romano - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 16:29:49 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/jpromanonet/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Basic CI/CD Pipeline with Webhooks on Linux ]]>
                </title>
                <description>
                    <![CDATA[ In the fast-paced world of software development, delivering high-quality applications quickly and reliably is crucial. This is where CI/CD (Continuous Integration and Continuous Delivery/Deployment) comes into play. CI/CD is a set of practices and to... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-a-basic-cicd-pipeline-with-webhooks-on-linux/</link>
                <guid isPermaLink="false">67995e567a54c877fce42276</guid>
                
                    <category>
                        <![CDATA[ Linux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ linux for beginners ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python 3 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ python beginner ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ci-cd ]]>
                    </category>
                
                    <category>
                        <![CDATA[ CI/CD ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan P. Romano ]]>
                </dc:creator>
                <pubDate>Tue, 28 Jan 2025 22:46:46 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737640144719/9035597c-0a69-4146-93cc-8bd659384169.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the fast-paced world of software development, delivering high-quality applications quickly and reliably is crucial. This is where <strong>CI/CD</strong> (Continuous Integration and Continuous Delivery/Deployment) comes into play.</p>
<p>CI/CD is a set of practices and tools designed to automate and streamline the process of integrating code changes, testing them, and deploying them to production. By adopting CI/CD, your team can reduce manual errors, speed up release cycles, and ensure that your code is always in a deployable state.</p>
<p>In this tutorial, we’ll focus on a beginner-friendly approach to setting up a basic CI/CD pipeline using Bitbucket, a Linux server, and Python with Flask. Specifically, we’ll create an automated process that pulls the latest changes from a Bitbucket repository to your Linux server whenever there’s a push or merge to a specific branch.</p>
<p>This process will be powered by Bitbucket webhooks and a simple Flask-based Python server that listens for incoming webhook events and triggers the deployment.</p>
<p>It’s important to note that CI/CD is a vast and complex field, and this tutorial is designed to provide a foundational understanding rather than to be an exhaustive guide.</p>
<p>We’ll cover the basics of setting up a CI/CD pipeline using tools that are accessible to beginners. Just keep in mind that real-world CI/CD systems often involve more advanced tools and configurations, such as containerization, orchestration, and multi-stage testing environments.</p>
<p>By the end of this tutorial, you’ll have a working example of how to automate deployments using Bitbucket, Linux, and Python, which you can build upon as you grow more comfortable with CI/CD concepts.</p>
<h3 id="heading-table-of-contents">Table of Contents:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-why-is-cicd-important">Why is CI/CD Important?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-1-set-up-a-webhook-in-bitbucket">Step 1: Set Up a Webhook in Bitbucket</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-set-up-the-flask-listener-on-your-linux-server">Step 2: Set Up the Flask Listener on Your Linux Server</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-expose-the-flask-app-optional">Step 3: Expose the Flask App (Optional)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-test-the-setup">Step 4: Test the Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-security-considerations">Step 5: Security Considerations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ol>
<h2 id="heading-why-is-cicd-important">Why is CI/CD Important?</h2>
<p>CI/CD has become a cornerstone of modern software development for several reasons. First and foremost, it accelerates the development process. By automating repetitive tasks like testing and deployment, developers can focus more on writing code and less on manual processes. This leads to faster delivery of new features and bug fixes, which is especially important in competitive markets where speed can be a differentiator.</p>
<p>Another key benefit of CI/CD is reduced errors and improved reliability. Automated testing ensures that every code change is rigorously checked for issues before it’s integrated into the main codebase. This minimizes the risk of introducing bugs that could disrupt the application or require costly fixes later. Automated deployment pipelines also reduce the likelihood of human error during the release process, ensuring that deployments are consistent and predictable.</p>
<p>CI/CD also fosters better collaboration among team members. In traditional development workflows, integrating code changes from multiple developers can be a time-consuming and error-prone process. With CI/CD, code is integrated and tested frequently, often multiple times a day. This means that conflicts are detected and resolved early, and the codebase remains in a stable state. As a result, teams can work more efficiently and with greater confidence, even when multiple contributors are working on different parts of the project simultaneously.</p>
<p>Finally, CI/CD supports continuous improvement and innovation. By automating the deployment process, teams can release updates to production more frequently and with less risk. This enables them to gather feedback from users faster and iterate on their products more effectively.</p>
<h3 id="heading-what-well-cover-in-this-tutorial">What We’ll Cover in This Tutorial</h3>
<p>In this tutorial, we’ll walk through the process of setting up a simple CI/CD pipeline that automates the deployment of code changes from a Bitbucket repository to a Linux server. Here’s what you’ll learn:</p>
<ol>
<li><p>How to configure a Bitbucket repository to send webhook notifications whenever there’s a push or merge to a specific branch.</p>
</li>
<li><p>How to set up a Flask-based Python server on your Linux server to listen for incoming webhook events.</p>
</li>
<li><p>How to write a script that pulls the latest changes from the repository and deploys them to the server.</p>
</li>
<li><p>How to test and troubleshoot your automated deployment process.</p>
</li>
</ol>
<p>By the end of this tutorial, you’ll have a working example of a basic CI/CD pipeline that you can customize and expand as needed. Let’s get started!</p>
<h2 id="heading-step-1-set-up-a-webhook-in-bitbucket"><strong>Step 1: Set Up a Webhook in Bitbucket</strong></h2>
<p>Before starting with the setup, let’s briefly explain what a <strong>webhook</strong> is and how it fits into our CI/CD process.</p>
<p>A webhook is a mechanism that allows one system to notify another system about an event in real-time. In the context of Bitbucket, a webhook can be configured to send an HTTP request (often a POST request with payload data) to a specified URL whenever a specific event occurs in your repository, such as a push to a branch or a pull request merge.</p>
<p>In our case, the webhook will notify our Flask-based Python server (running on your Linux server) whenever there’s a push or merge to a specific branch. This notification will trigger a script on the server to pull the latest changes from the repository and deploy them automatically. Essentially, the webhook acts as the bridge between Bitbucket and your server, enabling seamless automation of the deployment process.</p>
<p>Now that you understand the role of a webhook, let’s set one up in Bitbucket:</p>
<ol>
<li><p>Log in to Bitbucket and navigate to your repository.</p>
</li>
<li><p>On the left-hand sidebar, click on <strong>Settings</strong>.</p>
</li>
<li><p>Under the <strong>Workflow</strong> section, find and click on <strong>Webhooks</strong>.</p>
</li>
<li><p>Click the <strong>Add webhook</strong> button.</p>
</li>
<li><p>Enter a name for your webhook (for example, "Automatic Pull").</p>
</li>
<li><p>In the <strong>URL</strong> field, provide the URL to your server where the webhook will send the request. If you’re running a Flask app locally, this would be something like <a target="_blank" href="http://your-server-ip/pull-repo"><code>http://your-server-ip/pull-repo</code></a>. (For production environments, it’s highly recommended to use HTTPS to secure the communication between Bitbucket and your server.)</p>
</li>
<li><p>In the <strong>Triggers</strong> section, choose the events you want to listen to. For this example, we will select <strong>Push</strong> (and optionally, <strong>Pull Request Merged</strong> if you want to deploy after merges, too).</p>
</li>
<li><p>Save the webhook with a self-explanatory name so it’s easy to identify later.</p>
</li>
</ol>
<p>Once the webhook is set up, Bitbucket will send a POST request to the specified URL every time the selected event occurs. In the next steps, we’ll set up a Flask server to handle these incoming requests and trigger the deployment process.</p>
<p>Here is what you should see when you setup up the Bitbucket webhook</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738092826221/e0d96fd3-d843-4064-a08d-4de95b985800.png" alt="Bitbucket screen showing the user the creation of a webhook, where your server will pull the modifications when you push or merge in your reposiroty." class="image--center mx-auto" width="909" height="882" loading="lazy"></p>
<h2 id="heading-step-2-set-up-the-flask-listener-on-your-linux-server"><strong>Step 2: Set Up the Flask Listener on Your Linux Server</strong></h2>
<p>In the next step, you’ll set up a simple web server on your Linux machine that will listen for the webhook from Bitbucket. When it receives the notification, it will execute a <code>git pull</code> or a force pull (in case of local changes) to update the repository.</p>
<h3 id="heading-install-flask"><strong>Install Flask:</strong></h3>
<p>To create the Flask application, first install Flask by running:</p>
<pre><code class="lang-bash">pip install flask
</code></pre>
<h3 id="heading-create-the-flask-app"><strong>Create the Flask App:</strong></h3>
<p>Create a new Python script (for example, <a target="_blank" href="http://app.py"><code>app_repo_pull.py</code></a>) on your server and add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask
<span class="hljs-keyword">import</span> subprocess

app = Flask(__name__)

<span class="hljs-meta">@app.route('/pull-repo', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">pull_repo</span>():</span>
    <span class="hljs-keyword">try</span>:
        <span class="hljs-comment"># Fetch the latest changes from the remote repository</span>
        subprocess.run([<span class="hljs-string">"git"</span>, <span class="hljs-string">"-C"</span>, <span class="hljs-string">"/path/to/your/repository"</span>, <span class="hljs-string">"fetch"</span>], check=<span class="hljs-literal">True</span>)
        <span class="hljs-comment"># Force reset the local branch to match the remote 'test' branch</span>
        subprocess.run([<span class="hljs-string">"git"</span>, <span class="hljs-string">"-C"</span>, <span class="hljs-string">"/path/to/your/repository"</span>, <span class="hljs-string">"reset"</span>, <span class="hljs-string">"--hard"</span>, <span class="hljs-string">"origin/test"</span>], check=<span class="hljs-literal">True</span>)  <span class="hljs-comment"># Replace 'test' with your branch name</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Force pull successful"</span>, <span class="hljs-number">200</span>
    <span class="hljs-keyword">except</span> subprocess.CalledProcessError:
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Failed to force pull the repository"</span>, <span class="hljs-number">500</span>

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(host=<span class="hljs-string">'0.0.0.0'</span>, port=<span class="hljs-number">5000</span>)
</code></pre>
<p>Here’s what this code does:</p>
<ul>
<li><p><a target="_blank" href="http://subprocess.run"><code>subprocess.run</code></a><code>(["git", "-C", "/path/to/your/repository", "fetch"])</code>: This command fetches the latest changes from the remote repository without affecting the local working directory.</p>
</li>
<li><p><a target="_blank" href="http://subprocess.run"><code>subprocess.run</code></a><code>(["git", "-C", "/path/to/your/repository", "reset", "--hard", "origin/test"])</code>: This command performs a hard reset, forcing the local repository to match the remote <code>test</code> branch. Replace <code>test</code> with the name of your branch.</p>
</li>
</ul>
<p>Make sure to replace <code>/path/to/your/repository</code> with the actual path to your local Git repository.</p>
<h2 id="heading-step-3-expose-the-flask-app-optional"><strong>Step 3: Expose the Flask App (Optional)</strong></h2>
<p>If you want the Flask app to be accessible from outside your server, you need to expose it publicly. For this, you can set up a reverse proxy with NGINX. Here's how to do that:</p>
<p>First, install NGINX if you don't have it already by running this command:</p>
<pre><code class="lang-bash">sudo apt-get install nginx
</code></pre>
<p>Next, you’ll need to configure NGINX to proxy requests to your Flask app. Open the NGINX configuration file:</p>
<pre><code class="lang-bash">sudo nano /etc/nginx/sites-available/default
</code></pre>
<p>Modify the configuration to include this block:</p>
<pre><code class="lang-bash">server {
    listen 80;
    server_name your-server-ip;

    location /pull-repo {
        proxy_pass http://localhost:5000;
        proxy_set_header Host <span class="hljs-variable">$host</span>;
        proxy_set_header X-Real-IP <span class="hljs-variable">$remote_addr</span>;
        proxy_set_header X-Forwarded-For <span class="hljs-variable">$proxy_add_x_forwarded_for</span>;
        proxy_set_header X-Forwarded-Proto <span class="hljs-variable">$scheme</span>;
    }
}
</code></pre>
<p>Now just reload NGINX to apply the changes:</p>
<pre><code class="lang-bash">sudo systemctl reload nginx
</code></pre>
<h2 id="heading-step-4-test-the-setup"><strong>Step 4: Test the Setup</strong></h2>
<p>Now that everything is set up, go ahead and start the Flask app by executing this Python script:</p>
<pre><code class="lang-bash">python3 app_repo_pull.py
</code></pre>
<p>Now to test if everything is working:</p>
<ol>
<li><strong>Make a commit</strong>: Push a commit to the <code>test</code> branch in your Bitbucket repository. This action will trigger the webhook.</li>
</ol>
<ol>
<li><p><strong>Webhook trigger</strong>: The webhook will send a POST request to your server. The Flask app will receive this request, perform a force pull from the <code>test</code> branch, and update the local repository.</p>
</li>
<li><p><strong>Verify the pull</strong>: Check the log output of your Flask app or inspect the local repository to verify that the changes have been pulled and applied successfully.</p>
</li>
</ol>
<h2 id="heading-step-5-security-considerations"><strong>Step 5: Security Considerations</strong></h2>
<p>When exposing a Flask app to the internet, securing your server and application is crucial to protect it from unauthorized access, data breaches, and attacks. Here are the key areas to focus on:</p>
<h4 id="heading-1-use-a-secure-server-with-proper-firewall-rules"><strong>1. Use a Secure Server with Proper Firewall Rules</strong></h4>
<p>A secure server is one that is configured to minimize exposure to external threats. This involves using firewall rules, minimizing unnecessary services, and ensuring that only required ports are open for communication.</p>
<h5 id="heading-example-of-a-secure-server-setup"><strong>Example of a secure server setup:</strong></h5>
<ul>
<li><p><strong>Minimal software</strong>: Only install the software you need (for example, Python, Flask, NGINX) and remove unnecessary services.</p>
</li>
<li><p><strong>Operating system updates</strong>: Ensure your server's operating system is up-to-date with the latest security patches.</p>
</li>
<li><p><strong>Firewall configuration</strong>: Use a firewall to control incoming and outgoing traffic and limit access to your server.</p>
</li>
</ul>
<p>For example, a basic <strong>UFW (Uncomplicated Firewall)</strong> configuration on Ubuntu might look like this:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Allow SSH (port 22) for remote access</span>
sudo ufw allow ssh

<span class="hljs-comment"># Allow HTTP (port 80) and HTTPS (port 443) for web traffic</span>
sudo ufw allow http
sudo ufw allow https

<span class="hljs-comment"># Enable the firewall</span>
sudo ufw <span class="hljs-built_in">enable</span>

<span class="hljs-comment"># Check the status of the firewall</span>
sudo ufw status
</code></pre>
<p>In this case:</p>
<ul>
<li><p>The firewall allows incoming SSH connections on port 22, HTTP on port 80, and HTTPS on port 443.</p>
</li>
<li><p>Any unnecessary ports or services should be blocked by default to limit exposure to attacks.</p>
</li>
</ul>
<h5 id="heading-additional-firewall-rules"><strong>Additional Firewall Rules:</strong></h5>
<ul>
<li><p><strong>Limit access to webhook endpoint</strong>: Ideally, only allow traffic to the webhook endpoint from Bitbucket's IP addresses to prevent external access. You can set this up in your firewall or using your web server (for example, NGINX) by only accepting requests from Bitbucket's IP range.</p>
</li>
<li><p><strong>Deny all other incoming traffic</strong>: For any service that does not need to be exposed to the internet (for example, database ports), ensure those ports are blocked.</p>
</li>
</ul>
<h4 id="heading-2-add-authentication-to-the-flask-app"><strong>2. Add Authentication to the Flask App</strong></h4>
<p>Since your Flask app will be publicly accessible via the webhook URL, you should consider adding authentication to ensure only authorized users (such as Bitbucket's servers) can trigger the pull.</p>
<h5 id="heading-basic-authentication-example"><strong>Basic Authentication Example:</strong></h5>
<p>You can use a simple token-based authentication to secure your webhook endpoint. Here’s an example of how to modify your Flask app to require an authentication token:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, request, abort
<span class="hljs-keyword">import</span> subprocess

app = Flask(__name__)

<span class="hljs-comment"># Define a secret token for webhook verification</span>
SECRET_TOKEN = <span class="hljs-string">'your-secret-token'</span>

<span class="hljs-meta">@app.route('/pull-repo', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">pull_repo</span>():</span>
    <span class="hljs-comment"># Check if the request contains the correct token</span>
    token = request.headers.get(<span class="hljs-string">'X-Hub-Signature'</span>)
    <span class="hljs-keyword">if</span> token != SECRET_TOKEN:
        abort(<span class="hljs-number">403</span>)  <span class="hljs-comment"># Forbidden if the token is incorrect</span>

    <span class="hljs-keyword">try</span>:
        subprocess.run([<span class="hljs-string">"git"</span>, <span class="hljs-string">"-C"</span>, <span class="hljs-string">"/path/to/your/repository"</span>, <span class="hljs-string">"fetch"</span>], check=<span class="hljs-literal">True</span>)
        subprocess.run([<span class="hljs-string">"git"</span>, <span class="hljs-string">"-C"</span>, <span class="hljs-string">"/path/to/your/repository"</span>, <span class="hljs-string">"reset"</span>, <span class="hljs-string">"--hard"</span>, <span class="hljs-string">"origin/test"</span>], check=<span class="hljs-literal">True</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Force pull successful"</span>, <span class="hljs-number">200</span>
    <span class="hljs-keyword">except</span> subprocess.CalledProcessError:
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Failed to force pull the repository"</span>, <span class="hljs-number">500</span>

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    app.run(host=<span class="hljs-string">'0.0.0.0'</span>, port=<span class="hljs-number">5000</span>)
</code></pre>
<h5 id="heading-how-it-works"><strong>How it works:</strong></h5>
<ul>
<li><p>The <code>X-Hub-Signature</code> is a custom header that you add to the request when setting up the webhook in Bitbucket.</p>
</li>
<li><p>Only requests with the correct token will be allowed to trigger the pull. If the token is missing or incorrect, the request is rejected with a <code>403 Forbidden</code> response.</p>
</li>
</ul>
<p>You can also use more complex forms of authentication, such as OAuth or HMAC (Hash-based Message Authentication Code), but this simple token approach works for many cases.</p>
<h4 id="heading-3-use-https-for-secure-communication"><strong>3. Use HTTPS for Secure Communication</strong></h4>
<p>It’s crucial to encrypt the data transmitted between your Flask app and the Bitbucket webhook, as well as any sensitive data (such as tokens or passwords) being transmitted over the network. This ensures that attackers cannot intercept or modify the data.</p>
<h5 id="heading-why-https"><strong>Why HTTPS?</strong></h5>
<ul>
<li><p><strong>Data encryption</strong>: HTTPS encrypts the communication, ensuring that sensitive data like your authentication token is not exposed to man-in-the-middle attacks.</p>
</li>
<li><p><strong>Trust and integrity</strong>: HTTPS helps ensure that the data received by your server hasn’t been tampered with.</p>
</li>
</ul>
<h5 id="heading-using-lets-encrypt-to-secure-your-flask-app-with-ssl"><strong>Using Let’s Encrypt to Secure Your Flask App with SSL:</strong></h5>
<ol>
<li><strong>Install Certbot</strong> (the tool for obtaining Let’s Encrypt certificates):</li>
</ol>
<pre><code class="lang-bash">sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx
</code></pre>
<p><strong>Obtain a free SSL certificate for your domain</strong>:</p>
<pre><code class="lang-bash">sudo certbot --nginx -d your-domain.com
</code></pre>
<ul>
<li><p>This command will automatically configure Nginx to use HTTPS with a free SSL certificate from Let’s Encrypt.</p>
</li>
<li><p><strong>Ensure HTTPS is used</strong>: Make sure that your Flask app or Nginx configuration forces all traffic to use HTTPS. You can do this by setting up a redirection rule in Nginx:</p>
</li>
</ul>
<pre><code class="lang-bash">server {
    listen 80;
    server_name your-domain.com;

    <span class="hljs-comment"># Redirect HTTP to HTTPS</span>
    <span class="hljs-built_in">return</span> 301 https://<span class="hljs-variable">$host</span><span class="hljs-variable">$request_uri</span>;
}

server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    <span class="hljs-comment"># Other Nginx configuration...</span>
}
</code></pre>
<p><strong>Automatic Renewal</strong>: Let’s Encrypt certificates are valid for 90 days, so it’s important to set up automatic renewal:</p>
<pre><code class="lang-bash">sudo certbot renew --dry-run
</code></pre>
<p>This command tests the renewal process to make sure everything is working.</p>
<h4 id="heading-4-logging-and-monitoring"><strong>4. Logging and Monitoring</strong></h4>
<p>Implement logging and monitoring for your Flask app to track any unauthorized attempts, errors, or unusual activity:</p>
<ul>
<li><p><strong>Log requests</strong>: Log all incoming requests, including the IP address, request headers, and response status, so you can monitor for any suspicious activity.</p>
</li>
<li><p><strong>Use monitoring tools</strong>: Set up tools like <strong>Prometheus</strong>, <strong>Grafana</strong>, or <strong>New Relic</strong> to monitor server performance and app health.</p>
</li>
</ul>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this tutorial, we explored how to set up a simple, beginner-friendly CI/CD pipeline that automates deployments using Bitbucket, a Linux server, and Python with Flask. Here’s a recap of what you’ve learned:</p>
<ol>
<li><p><strong>CI/CD Fundamentals</strong>: We discussed the basics of Continuous Integration (CI) and Continuous Delivery/Deployment (CD), which are essential practices for automating the integration, testing, and deployment of code. You learned how CI/CD helps speed up development, reduce errors, and improve collaboration among developers.</p>
</li>
<li><p><strong>Setting Up Bitbucket Webhooks</strong>: You learned how to configure a Bitbucket webhook to notify your server whenever there’s a push or merge to a specific branch. This webhook serves as a trigger to initiate the deployment process automatically.</p>
</li>
<li><p><strong>Creating a Flask-based Webhook Listener</strong>: We showed you how to set up a Flask app on your Linux server to listen for incoming webhook requests from Bitbucket. This Flask app receives the notifications and runs the necessary Git commands to pull and deploy the latest changes.</p>
</li>
<li><p><strong>Automating the Deployment Process</strong>: Using Python and Flask, we automated the process of pulling changes from the Bitbucket repository and performing a force pull to ensure the latest code is deployed. You also learned how to configure the server to expose the Flask app and accept requests securely.</p>
</li>
<li><p><strong>Security Considerations</strong>: We covered critical security steps to protect your deployment process:</p>
<ul>
<li><p><strong>Firewall Rules</strong>: We discussed configuring firewall rules to limit exposure and ensure only authorized traffic (from Bitbucket) can access your server.</p>
</li>
<li><p><strong>Authentication</strong>: We added token-based authentication to ensure only authorized requests can trigger deployments.</p>
</li>
<li><p><strong>HTTPS</strong>: We explained how to secure the communication between your server and Bitbucket using SSL certificates from Let's Encrypt.</p>
</li>
<li><p><strong>Logging and Monitoring</strong>: Lastly, we recommended setting up logging and monitoring to keep track of any unusual activity or errors.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-next-steps"><strong>Next Steps</strong></h3>
<p>By the end of this tutorial, you now have a working example of an automated deployment pipeline. While this is a basic implementation, it serves as a foundation you can build on. As you grow more comfortable with CI/CD, you can explore advanced topics like:</p>
<ul>
<li><p>Multi-stage deployment pipelines</p>
</li>
<li><p>Integration with containerization tools like Docker</p>
</li>
<li><p>More complex testing and deployment strategies</p>
</li>
<li><p>Use of orchestration tools like Kubernetes for scaling</p>
</li>
</ul>
<p>CI/CD practices are continually evolving, and by mastering the basics, you’ve set yourself up for success as you expand your skills in this area. Happy automating and thank you for reading!</p>
<p>You can <a target="_blank" href="https://github.com/jpromanonet/ci_cd_fcc/tree/main">fork the code from here</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ PyGame Tutorial – How to Build a Bouncing Ball Game ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, you'll learn how to create a simple yet funny bouncing ball game using the PyGame library. Whether you're a beginner seeking to grasp the fundamentals of game development or an enthusiast eager to explore PyGame's capabilities, this... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/pygame-tutorial-build-a-bouncing-game/</link>
                <guid isPermaLink="false">66d45f67a326133d124409f9</guid>
                
                    <category>
                        <![CDATA[ Game Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pygame ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan P. Romano ]]>
                </dc:creator>
                <pubDate>Tue, 23 Jan 2024 22:46:54 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/bouncing_ball.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, you'll learn how to create a simple yet funny bouncing ball game using the PyGame library.</p>
<p>Whether you're a beginner seeking to grasp the fundamentals of game development or an enthusiast eager to explore PyGame's capabilities, this article is your guide to crafting a simple yet engaging game.</p>
<p>You just need to break down the steps, read the code, and enjoy the ride!</p>
<p>At the end of this tutorial, your game should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/bouncing_game.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-the-development-environment">How to set up the development environment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-defining-the-game-concept">Defining the game concept</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-app-initialization">App initialization</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-pygame-instance">How to create a PyGame instance</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-the-game-screens">How to create the game screens</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-main-game-loop">Main game loop</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-how-to-set-up-the-development-environment">How to Set Up the Development Environment</h2>
<h3 id="heading-tools-and-software">Tools and Software</h3>
<p>Before you get into the coding adventure, let's talk about the tools that will fuel your creativity.</p>
<h4 id="heading-python">Python</h4>
<p>You'll be using Python, a versatile and beginner-friendly programming language. Its clean syntax and extensive library support make it an excellent choice for game development.</p>
<p>If you don't have Python installed, head over to <a target="_blank" href="https://www.python.org/">python.org</a> to download and install the latest version.</p>
<h4 id="heading-pygame">PyGame</h4>
<p>Your secret weapon for this project. PyGame, a set of Python modules, simplifies game development by handling multimedia elements like images and sounds. It's the engine that will power your game.</p>
<p>To install PyGame, you can use the following command in your terminal or command prompt:</p>
<pre><code class="lang-bash">pip install pygame
</code></pre>
<h4 id="heading-text-editor">Text Editor</h4>
<p>Whether it's VSCode, PyCharm, or Thonny, these environments offer features like syntax highlighting and debugging tools. Choose the one you're most comfortable with, and let's get ready to write some code!</p>
<p>I will be using VSCode but feel free to use whichever you like. If you feel adventurous, you can try Thonny!</p>
<p>Now that you're armed with the right tools, let's jump into the code and bring your game to life.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/screenshot-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>This is Thonny</em></p>
<h2 id="heading-defining-the-game-concept">Defining the Game Concept</h2>
<h3 id="heading-game-concept-and-mechanics">Game Concept and Mechanics</h3>
<p>Let's break down the core concepts and mechanics you'll be implementing.</p>
<p><strong>Platform Control:</strong></p>
<ul>
<li><p>Objective: Use arrow keys to move the platform left or right.</p>
</li>
<li><p>Implementation: Your platform moves horizontally based on key input.</p>
</li>
<li><p>Limitations: Ensure the platform stays within the screen boundaries.</p>
</li>
</ul>
<p><strong>Bouncing Ball Dynamics:</strong></p>
<ul>
<li><p>Objective: Guide the bouncing ball across the screen.</p>
</li>
<li><p>Implementation: The ball moves independently, bouncing off walls and the platform.</p>
</li>
<li><p>Interaction: Score points each time the ball successfully bounces off the platform.</p>
</li>
</ul>
<p><strong>Scoring System:</strong></p>
<ul>
<li><p>Objective: Accumulate points based on successful bounces.</p>
</li>
<li><p>Implementation: Your coding determines the scoring system.</p>
</li>
<li><p>Challenge: Optimize the scoring mechanism for higher scores.</p>
</li>
</ul>
<p><strong>Level Progression:</strong></p>
<ul>
<li><p>Objective: Advance through levels as your score reaches milestones.</p>
</li>
<li><p>Implementation: With every 10 points, you progress to a new level.</p>
</li>
<li><p>Challenge: Expect increased difficulty and complexity with each level.</p>
</li>
</ul>
<p><strong>Dynamic Platform Color:</strong></p>
<ul>
<li><p>Objective: Platform color changes with each level, adding a visual dynamic.</p>
</li>
<li><p>Implementation: Colors are randomly generated upon reaching a new level.</p>
</li>
<li><p>Aesthetic Touch: Adds variety and excitement to the gaming experience.</p>
</li>
</ul>
<p><strong>Lives and Game Over:</strong></p>
<ul>
<li><p>Objective: Avoid letting the ball fall off the screen to maintain lives.</p>
</li>
<li><p>Implementation: Lives decrease with missed bounces. Game over occurs when lives run out (you have only 3 lives).</p>
</li>
<li><p>Restart: After game over, restart with three lives and a fresh score.</p>
</li>
</ul>
<h2 id="heading-how-to-code-the-game">How to Code the Game</h2>
<h3 id="heading-app-initialization">App initialization</h3>
<p>In this section, you'll define constants such as screen dimensions, ball and platform properties, and colors.</p>
<p>You'll also initialize PyGame, set up the display screen, and create a clock object to control the frame rate.</p>
<p>Then you'll initialize variables for the game, including ball position, speed, platform position, speed, score, lives, and current level.</p>
<p>Here's the code to do all that:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pygame
<span class="hljs-keyword">import</span> sys
<span class="hljs-keyword">import</span> random

<span class="hljs-comment"># Constants</span>
WIDTH, HEIGHT = <span class="hljs-number">800</span>, <span class="hljs-number">600</span>
BALL_RADIUS = <span class="hljs-number">20</span>
PLATFORM_WIDTH, PLATFORM_HEIGHT = <span class="hljs-number">100</span>, <span class="hljs-number">10</span>
FPS = <span class="hljs-number">60</span>
BLACK = (<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>)
WHITE = (<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>)
RED = (<span class="hljs-number">255</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>)
YELLOW = (<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0</span>)
ORANGE = (<span class="hljs-number">255</span>, <span class="hljs-number">165</span>, <span class="hljs-number">0</span>)
LIGHT_BLUE = (<span class="hljs-number">173</span>, <span class="hljs-number">216</span>, <span class="hljs-number">230</span>)  <span class="hljs-comment"># Light blue color for the level indicator</span>
</code></pre>
<p>Let's break down the code step by step:</p>
<p><strong>Importing Libraries:</strong></p>
<ul>
<li><p><code>import pygame</code>: Imports the Pygame library, which is used for developing games in Python.</p>
</li>
<li><p><code>import sys</code>: Imports the sys module, providing access to some variables used or maintained by the interpreter and functions that interact with the interpreter.</p>
</li>
</ul>
<p><strong>Constants:</strong></p>
<ul>
<li><p><code>WIDTH, HEIGHT = 800, 600</code>: Defines the dimensions of the game window.</p>
</li>
<li><p><code>BALL_RADIUS = 20</code>: Specifies the radius of the bouncing ball.</p>
</li>
<li><p><code>PLATFORM_WIDTH, PLATFORM_HEIGHT = 100, 10</code>: Sets the dimensions of the platform.</p>
</li>
<li><p><code>FPS = 60</code>: Defines the frames per second, controlling the speed of the game.</p>
</li>
<li><p>Various color constants like <code>BLACK</code>, <code>WHITE</code>, <code>RED</code>, <code>YELLOW</code>, <code>ORANGE</code>, and <code>LIGHT_BLUE</code> represent RGB values for colors used in the game.</p>
</li>
</ul>
<h2 id="heading-how-to-create-a-pygame-instance">How to Create a PyGame Instance</h2>
<p>Now you're going to create the PyGame window and define some global variables that you'll use for every level of the game:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Initialize Pygame</span>
pygame.init()

<span class="hljs-comment"># Create the screen</span>
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(<span class="hljs-string">"Bouncing Ball Game"</span>)
font = pygame.font.Font(<span class="hljs-literal">None</span>, <span class="hljs-number">36</span>)

<span class="hljs-comment"># Clock to control the frame rate</span>
clock = pygame.time.Clock()

<span class="hljs-comment"># Initialize variables for the game</span>
ball_pos = [WIDTH // <span class="hljs-number">2</span>, HEIGHT // <span class="hljs-number">2</span>]
ball_speed = [random.uniform(<span class="hljs-number">2</span>, <span class="hljs-number">4</span>), random.uniform(<span class="hljs-number">2</span>, <span class="hljs-number">4</span>)]  <span class="hljs-comment"># Faster starting speed</span>
platform_pos = [WIDTH // <span class="hljs-number">2</span> - PLATFORM_WIDTH // <span class="hljs-number">2</span>, HEIGHT - PLATFORM_HEIGHT - <span class="hljs-number">10</span>]
platform_speed = <span class="hljs-number">10</span>
score = <span class="hljs-number">0</span>
lives = <span class="hljs-number">3</span>
current_level = <span class="hljs-number">1</span>
platform_color = ORANGE  <span class="hljs-comment"># Initialize platform color</span>
</code></pre>
<p><strong>Pygame Initialization:</strong></p>
<ul>
<li><code>pygame.init()</code>: Initializes the Pygame library.</li>
</ul>
<p><strong>Create the Game Window:</strong></p>
<ul>
<li><p><code>screen = pygame.display.set_mode((WIDTH, HEIGHT))</code>: Creates the game window with the specified dimensions.</p>
</li>
<li><p><code>pygame.display.set_caption("Bouncing Ball Game")</code>: Sets the title of the game window.</p>
</li>
<li><p><code>font = pygame.font.Font(None, 36)</code>: Initializes a font object for rendering text.</p>
</li>
</ul>
<p><strong>Clock for Frame Rate Control:</strong></p>
<ul>
<li><code>clock = pygame.time.Clock()</code>: Creates a clock object to control the frame rate.</li>
</ul>
<p><strong>Game Variables Initialization:</strong></p>
<ul>
<li><p><code>ball_pos = [WIDTH // 2, HEIGHT // 2]</code>: Initializes the starting position of the ball at the center of the screen.</p>
</li>
<li><p><code>ball_speed = [random.uniform(2, 4), random.uniform(2, 4)]</code>: Initializes the starting speed of the ball with random values.</p>
</li>
<li><p><code>platform_pos = [WIDTH // 2 - PLATFORM_WIDTH // 2, HEIGHT - PLATFORM_HEIGHT - 10]</code>: Initializes the starting position of the platform.</p>
</li>
<li><p><code>platform_speed = 10</code>: Sets the speed at which the platform moves.</p>
</li>
<li><p><code>score = 0</code>: Initializes the player's score.</p>
</li>
<li><p><code>lives = 3</code>: Initializes the number of lives the player has.</p>
</li>
<li><p><code>current_level = 1</code>: Initializes the current level of the game.</p>
</li>
<li><p><code>platform_color = ORANGE</code>: Initializes the color of the platform.</p>
</li>
</ul>
<h2 id="heading-how-to-create-the-game-screens">How to Create the Game Screens</h2>
<p>You will create at least three screens, one for start the game, one for winning the game, and one for losing the game. You can use the following code to do all that:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Functions for screens</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start_screen</span>():</span>
    screen.fill(BLACK)
    show_text_on_screen(<span class="hljs-string">"Bouncing Ball Game"</span>, <span class="hljs-number">50</span>, HEIGHT // <span class="hljs-number">4</span>)
    show_text_on_screen(<span class="hljs-string">"Press any key to start..."</span>, <span class="hljs-number">30</span>, HEIGHT // <span class="hljs-number">3</span>)
    show_text_on_screen(<span class="hljs-string">"Move the platform with arrow keys..."</span>, <span class="hljs-number">30</span>, HEIGHT // <span class="hljs-number">2</span>)
    pygame.display.flip()
    wait_for_key()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">game_over_screen</span>():</span>
    screen.fill(BLACK)
    show_text_on_screen(<span class="hljs-string">"Game Over"</span>, <span class="hljs-number">50</span>, HEIGHT // <span class="hljs-number">3</span>)
    show_text_on_screen(<span class="hljs-string">f"Your final score: <span class="hljs-subst">{score}</span>"</span>, <span class="hljs-number">30</span>, HEIGHT // <span class="hljs-number">2</span>)
    show_text_on_screen(<span class="hljs-string">"Press any key to restart..."</span>, <span class="hljs-number">20</span>, HEIGHT * <span class="hljs-number">2</span> // <span class="hljs-number">3</span>)
    pygame.display.flip()
    wait_for_key()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">victory_screen</span>():</span>
    screen.fill(BLACK)
    show_text_on_screen(<span class="hljs-string">"Congratulations!"</span>, <span class="hljs-number">50</span>, HEIGHT // <span class="hljs-number">3</span>)
    show_text_on_screen(<span class="hljs-string">f"You've won with a score of <span class="hljs-subst">{score}</span>"</span>, <span class="hljs-number">30</span>, HEIGHT // <span class="hljs-number">2</span>)
    show_text_on_screen(<span class="hljs-string">"Press any key to exit..."</span>, <span class="hljs-number">20</span>, HEIGHT * <span class="hljs-number">2</span> // <span class="hljs-number">3</span>)
    pygame.display.flip()
    wait_for_key()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wait_for_key</span>():</span>
    waiting = <span class="hljs-literal">True</span>
    <span class="hljs-keyword">while</span> waiting:
        <span class="hljs-keyword">for</span> event <span class="hljs-keyword">in</span> pygame.event.get():
            <span class="hljs-keyword">if</span> event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            <span class="hljs-keyword">elif</span> event.type == pygame.KEYDOWN:
                waiting = <span class="hljs-literal">False</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show_text_on_screen</span>(<span class="hljs-params">text, font_size, y_position</span>):</span>
    font = pygame.font.Font(<span class="hljs-literal">None</span>, font_size)
    text_render = font.render(text, <span class="hljs-literal">True</span>, WHITE)
    text_rect = text_render.get_rect(center=(WIDTH // <span class="hljs-number">2</span>, y_position))
    screen.blit(text_render, text_rect)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">change_platform_color</span>():</span>
    <span class="hljs-keyword">return</span> (random.randint(<span class="hljs-number">0</span>, <span class="hljs-number">255</span>), random.randint(<span class="hljs-number">0</span>, <span class="hljs-number">255</span>), random.randint(<span class="hljs-number">0</span>, <span class="hljs-number">255</span>))
</code></pre>
<p>Let's go through the functions:</p>
<p><code>start_screen()</code> Function:</p>
<ul>
<li><p>Clears the screen with a black background using <code>screen.fill(BLACK)</code>.</p>
</li>
<li><p>Displays the game title and instructions using <code>show_text_on_screen</code>.</p>
</li>
<li><p>Flips the display to make the changes visible with <code>pygame.display.flip()</code>.</p>
</li>
<li><p>Calls <code>wait_for_key()</code> to wait for a key press before proceeding.</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/image-105.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><code>game_over_screen()</code> Function:</p>
<ul>
<li><p>Clears the screen with a black background.</p>
</li>
<li><p>Displays the game over message, the final score, and instructions for restarting.</p>
</li>
<li><p>Flips the display.</p>
</li>
<li><p>Calls <code>wait_for_key()</code> to wait for a key press.</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/image-106.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><code>victory_screen()</code> Function:</p>
<ul>
<li><p>Clears the screen with a black background.</p>
</li>
<li><p>Displays a congratulatory message, the final score, and instructions for exiting.</p>
</li>
<li><p>Flips the display.</p>
</li>
<li><p>Calls <code>wait_for_key()</code> to wait for a key press.</p>
</li>
</ul>
<p><code>wait_for_key()</code> Function:</p>
<ul>
<li><p>Waits for either a quit event (closing the game window) or a key press event.</p>
</li>
<li><p>If the event is quitting, it exits the game using <code>pygame.quit()</code> and <code>sys.exit()</code>.</p>
</li>
<li><p>If the event is a key press, it breaks out of the waiting loop.</p>
</li>
</ul>
<p><code>show_text_on_screen(text, font_size, y_position)</code> Function:</p>
<ul>
<li><p>Renders text on the screen with the specified font size and Y position.</p>
</li>
<li><p>Uses the <code>pygame.font.Font</code> class to create a font object.</p>
</li>
<li><p>Renders the text onto a surface with the specified color (white in this case).</p>
</li>
<li><p>Positions the text in the center of the screen at the specified Y position.</p>
</li>
<li><p>Blits (draws) the text onto the game screen.</p>
</li>
</ul>
<p><code>change_platform_color()</code> Function:</p>
<ul>
<li>Returns a random RGB color for changing the platform color.</li>
</ul>
<p>These functions handle different aspects of the game screens, user interactions, and display of text. They contribute to the overall structure and user experience of the game.</p>
<h2 id="heading-main-game-loop">Main Game Loop</h2>
<p>And now, you'll code the main loop of the game with it's applied mechanics. Let's check out the code first and then the explanation.</p>
<p>This is the longest block of code in this tutorial, so be patient – it's worth it.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Main game loop</span>
start_screen()
game_running = <span class="hljs-literal">True</span>

<span class="hljs-keyword">while</span> game_running:
    <span class="hljs-keyword">for</span> event <span class="hljs-keyword">in</span> pygame.event.get():
        <span class="hljs-keyword">if</span> event.type == pygame.QUIT:
            game_running = <span class="hljs-literal">False</span>

    keys = pygame.key.get_pressed()

    <span class="hljs-comment"># Move the platform</span>
    platform_pos[<span class="hljs-number">0</span>] += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * platform_speed
    platform_pos[<span class="hljs-number">1</span>] += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * platform_speed

    <span class="hljs-comment"># Ensure the platform stays within the screen boundaries</span>
    platform_pos[<span class="hljs-number">0</span>] = max(<span class="hljs-number">0</span>, min(platform_pos[<span class="hljs-number">0</span>], WIDTH - PLATFORM_WIDTH))
    platform_pos[<span class="hljs-number">1</span>] = max(<span class="hljs-number">0</span>, min(platform_pos[<span class="hljs-number">1</span>], HEIGHT - PLATFORM_HEIGHT))

    <span class="hljs-comment"># Move the ball</span>
    ball_pos[<span class="hljs-number">0</span>] += ball_speed[<span class="hljs-number">0</span>]
    ball_pos[<span class="hljs-number">1</span>] += ball_speed[<span class="hljs-number">1</span>]

    <span class="hljs-comment"># Bounce off the walls</span>
    <span class="hljs-keyword">if</span> ball_pos[<span class="hljs-number">0</span>] &lt;= <span class="hljs-number">0</span> <span class="hljs-keyword">or</span> ball_pos[<span class="hljs-number">0</span>] &gt;= WIDTH:
        ball_speed[<span class="hljs-number">0</span>] = -ball_speed[<span class="hljs-number">0</span>]

    <span class="hljs-keyword">if</span> ball_pos[<span class="hljs-number">1</span>] &lt;= <span class="hljs-number">0</span>:
        ball_speed[<span class="hljs-number">1</span>] = -ball_speed[<span class="hljs-number">1</span>]

    <span class="hljs-comment"># Check if the ball hits the platform</span>
    <span class="hljs-keyword">if</span> (
        platform_pos[<span class="hljs-number">0</span>] &lt;= ball_pos[<span class="hljs-number">0</span>] &lt;= platform_pos[<span class="hljs-number">0</span>] + PLATFORM_WIDTH
        <span class="hljs-keyword">and</span> platform_pos[<span class="hljs-number">1</span>] &lt;= ball_pos[<span class="hljs-number">1</span>] &lt;= platform_pos[<span class="hljs-number">1</span>] + PLATFORM_HEIGHT
    ):
        ball_speed[<span class="hljs-number">1</span>] = -ball_speed[<span class="hljs-number">1</span>]
        score += <span class="hljs-number">1</span>

    <span class="hljs-comment"># Check if the player advances to the next level</span>
    <span class="hljs-keyword">if</span> score &gt;= current_level * <span class="hljs-number">10</span>:
        current_level += <span class="hljs-number">1</span>
        ball_pos = [WIDTH // <span class="hljs-number">2</span>, HEIGHT // <span class="hljs-number">2</span>]
        ball_speed = [random.uniform(<span class="hljs-number">2</span>, <span class="hljs-number">4</span>), random.uniform(<span class="hljs-number">2</span>, <span class="hljs-number">4</span>)]  <span class="hljs-comment"># Randomize the ball speed</span>
        platform_color = change_platform_color()

    <span class="hljs-comment"># Check if the ball falls off the screen</span>
    <span class="hljs-keyword">if</span> ball_pos[<span class="hljs-number">1</span>] &gt;= HEIGHT:
        <span class="hljs-comment"># Decrease lives</span>
        lives -= <span class="hljs-number">1</span>
        <span class="hljs-keyword">if</span> lives == <span class="hljs-number">0</span>:
            game_over_screen()
            start_screen()  <span class="hljs-comment"># Restart the game after game over</span>
            score = <span class="hljs-number">0</span>
            lives = <span class="hljs-number">3</span>
            current_level = <span class="hljs-number">1</span>
        <span class="hljs-keyword">else</span>:
            <span class="hljs-comment"># Reset the ball position</span>
            ball_pos = [WIDTH // <span class="hljs-number">2</span>, HEIGHT // <span class="hljs-number">2</span>]
            <span class="hljs-comment"># Randomize the ball speed</span>
            ball_speed = [random.uniform(<span class="hljs-number">2</span>, <span class="hljs-number">4</span>), random.uniform(<span class="hljs-number">2</span>, <span class="hljs-number">4</span>)]

    <span class="hljs-comment"># Clear the screen</span>
    screen.fill(BLACK)

    <span class="hljs-comment"># Draw the ball</span>
    pygame.draw.circle(screen, WHITE, (int(ball_pos[<span class="hljs-number">0</span>]), int(ball_pos[<span class="hljs-number">1</span>])), BALL_RADIUS)

    <span class="hljs-comment"># Draw the platform</span>
    pygame.draw.rect(screen, platform_color, (int(platform_pos[<span class="hljs-number">0</span>]), int(platform_pos[<span class="hljs-number">1</span>]), PLATFORM_WIDTH, PLATFORM_HEIGHT))

    <span class="hljs-comment"># Display information</span>
    info_line_y = <span class="hljs-number">10</span>  <span class="hljs-comment"># Adjust the vertical position as needed</span>
    info_spacing = <span class="hljs-number">75</span>  <span class="hljs-comment"># Adjust the spacing as needed</span>

    <span class="hljs-comment"># Draw the score in an orange rectangle at the top left</span>
    score_text = font.render(<span class="hljs-string">f"Score: <span class="hljs-subst">{score}</span>"</span>, <span class="hljs-literal">True</span>, WHITE)
    score_rect = score_text.get_rect(topleft=(<span class="hljs-number">10</span>, info_line_y))
    pygame.draw.rect(screen, ORANGE, score_rect.inflate(<span class="hljs-number">10</span>, <span class="hljs-number">5</span>))
    screen.blit(score_text, score_rect)

    <span class="hljs-comment"># Draw the level indicator in a light-blue rectangle at the top left (next to the score)</span>
    level_text = font.render(<span class="hljs-string">f"Level: <span class="hljs-subst">{current_level}</span>"</span>, <span class="hljs-literal">True</span>, WHITE)
    level_rect = level_text.get_rect(topleft=(score_rect.topright[<span class="hljs-number">0</span>] + info_spacing, info_line_y))
    pygame.draw.rect(screen, LIGHT_BLUE, level_rect.inflate(<span class="hljs-number">10</span>, <span class="hljs-number">5</span>))
    screen.blit(level_text, level_rect)

    <span class="hljs-comment"># Draw the lives in a red rectangle at the top left (next to the level)</span>
    lives_text = font.render(<span class="hljs-string">f"Lives: <span class="hljs-subst">{lives}</span>"</span>, <span class="hljs-literal">True</span>, WHITE)
    lives_rect = lives_text.get_rect(topleft=(level_rect.topright[<span class="hljs-number">0</span>] + info_spacing, info_line_y))
    pygame.draw.rect(screen, RED, lives_rect.inflate(<span class="hljs-number">10</span>, <span class="hljs-number">5</span>))
    screen.blit(lives_text, lives_rect)

    <span class="hljs-comment"># Update the display</span>
    pygame.display.flip()

    <span class="hljs-comment"># Control the frame rate</span>
    clock.tick(FPS)

<span class="hljs-comment"># Quit Pygame</span>
pygame.quit()
</code></pre>
<p>Alright, that was a lot – but here's what we did in the above code:</p>
<p><strong>Initialization and Start Screen:</strong></p>
<ul>
<li><p>Calls <code>start_screen()</code> to display the initial screen with instructions.</p>
</li>
<li><p>Sets <code>game_running</code> to <code>True</code> to initiate the main game loop.</p>
</li>
</ul>
<p><strong>Main Game Loop:</strong></p>
<ul>
<li>Continues until <code>game_running</code> becomes <code>False</code> (for example, when the user closes the game window).</li>
</ul>
<p><strong>Event Handling:</strong></p>
<ul>
<li><p>Checks for events using <code>pygame.event.get()</code>.</p>
</li>
<li><p>If a quit event (closing the game window) is detected, sets <code>game_running</code> to <code>False</code> to exit the loop.</p>
</li>
</ul>
<p><strong>Platform Movement:</strong></p>
<ul>
<li><p>Reads the state of the arrow keys using <code>pygame.key.get_pressed()</code>.</p>
</li>
<li><p>Adjusts the platform position based on arrow key inputs.</p>
</li>
<li><p>Ensures the platform stays within the screen boundaries.</p>
</li>
</ul>
<p><strong>Ball Movement and Bouncing:</strong></p>
<ul>
<li><p>Updates the ball's position based on its speed.</p>
</li>
<li><p>Implements bouncing off the walls by reversing the speed when reaching the screen edges.</p>
</li>
</ul>
<p><strong>Collision Detection:</strong></p>
<ul>
<li><p>Checks if the ball hits the platform by comparing positions.</p>
</li>
<li><p>If a collision occurs, the ball's vertical speed is reversed, and the player scores a point.</p>
</li>
</ul>
<p><strong>Level Progression:</strong></p>
<ul>
<li><p>Checks if the player has scored enough points to advance to the next level.</p>
</li>
<li><p>If so, increments the level, resets the ball's position, randomizes its speed, and changes the platform color.</p>
</li>
</ul>
<p><strong>Checking for Game Over:</strong></p>
<ul>
<li><p>Monitors if the ball falls off the screen.</p>
</li>
<li><p>Decreases the number of lives if the ball is below the screen.</p>
</li>
<li><p>If lives run out, displays the game over screen, restarts the game, and resets score, lives, and level.</p>
</li>
</ul>
<p><strong>Screen Rendering:</strong></p>
<ul>
<li><p>Clears the screen with a black background.</p>
</li>
<li><p>Draws the ball and platform on the screen.</p>
</li>
<li><p>Displays score, level, and lives information in rectangles with specific colors.</p>
</li>
</ul>
<p><strong>Display Update and Frame Rate Control:</strong></p>
<ul>
<li><p>Updates the display to show the changes.</p>
</li>
<li><p>Controls the frame rate with <code>clock.tick(FPS)</code>.</p>
</li>
</ul>
<p><strong>Game Termination:</strong></p>
<ul>
<li>Exits PyGame and terminates the program when the main loop is exited.</li>
</ul>
<p>This structure ensures continuous gameplay, handling user input, updating game state, and providing visual feedback to the player.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you've navigated through the intricacies of several key functions that form the backbone of your bouncing ball game.</p>
<p>Let's recap their roles:</p>
<p>The <code>start_screen()</code> function clears the screen with a black background, displays the game title and instructions, flips the display for visibility, and waits for a key press using <code>wait_for_key()</code>.</p>
<p>The <code>game_over_screen()</code> function clears the screen with a black background, displays the game over message, final score, and restart instructions, flips the display, and waits for a key press with <code>wait_for_key()</code>.</p>
<p>The <code>victory_screen()</code> function clears the screen with a black background, displays a congratulatory message, final score, and exit instructions, flips the display, and waits for a key press with <code>wait_for_key()</code>.</p>
<p>The <code>wait_for_key()</code> function waits for either a quit event (closing the game window) or a key press event. It exits the game if quitting, and breaks out of the waiting loop if a key is pressed.</p>
<p>The <code>show_text_on_screen(text, font_size, y_position)</code> function renders text on the screen with specified attributes, utilizes the <code>pygame.font.Font</code> class for creating a font object, and positions and draws the text in the center of the screen.</p>
<p>And the <code>change_platform_color()</code> function returns a random RGB color for changing the platform color.</p>
<p>Following these functions, you delved into the main game loop, the heart of our game. It orchestrates the game's mechanics, including event handling, platform and ball movement, collision detection, level progression, and game termination.</p>
<p>You witnessed how this loop ensures continuous gameplay, responsive user interactions, and dynamic visuals.</p>
<p>Now that you're equipped with the understanding of these functions and the main loop, you have the knowledge to experiment, tweak, and expand your game. Feel empowered to embark on your journey of game development, explore new features, and create unique gaming experiences. Happy coding!</p>
<p>If you want to download the code or play the game, you can find it here:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/jpromanonet/bouncing_ball_game">https://github.com/jpromanonet/bouncing_ball_game</a></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ PyGame Tutorial – How to Build an Alien Abduction game ]]>
                </title>
                <description>
                    <![CDATA[ Ever since I was a kid, I've been hooked on video games. My first experience with coding involved kind of a wild project – a Tron races simulator in Quick Basic on an ancient IBM computer (I was like 6 years old, so I didn't really understand what I ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/pygame-tutorial-alien-abduction-game/</link>
                <guid isPermaLink="false">66d45f6538f2dc3808b790b5</guid>
                
                    <category>
                        <![CDATA[ Game Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pygame ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan P. Romano ]]>
                </dc:creator>
                <pubDate>Tue, 02 Jan 2024 23:55:29 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/12/alien_abduction_game.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Ever since I was a kid, I've been hooked on video games. My first experience with coding involved kind of a wild project – a Tron races simulator in Quick Basic on an ancient IBM computer (I was like 6 years old, so I didn't really understand what I was doing).</p>
<p>Fast forward through years of coding and here I am, still writing software and going into the world of game development.</p>
<p>With my sights set on becoming an indie game developer, I decided to explore PyGame, given my "fluency" in Python with teaching it and all.</p>
<p>After some brainstorming, I landed on a quirky concept: a game where you play as an alien cruising around in a UFO. Your mission? Hit a specific abduction quota each week to dodge sanctions from the Intergalactic Federation.</p>
<p>I won't lie, I was heavily inspired by the old "Luna lander" that I had in the same old IBM computer.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/image-65.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Black and White Luna Lander screen shot</em></p>
<h3 id="heading-why-i-think-making-games-is-cooler-than-your-average-coding-project">Why I think making games is cooler than your average coding project</h3>
<p>So, imagine you're coding, and suddenly it hits you – games! Yep, we're talking about the stuff that turns a screen into an interactive universe where you're not just a coder – you're a wizard creating spells (or lines of code) that make things move, shoot, and explode without legal repercussions.</p>
<p>Here's why diving into game development is like finding the secret level into software development:</p>
<ol>
<li><p><strong>It's coding with a purpose:</strong> Forget boring programs – you're creating a universe where aliens abduct cows because...why not?</p>
</li>
<li><p><strong>No more lone wolf coding:</strong> Games need more than code. They also need stories, characters, and cool graphics. Suddenly, you're not just a coder – you're a one-person army conquering design, storytelling, and maybe a bit of sound engineering.</p>
</li>
<li><p><strong>It's like LEGO for coders:</strong> You get to build stuff, break it, and then build it again! Game development is all about trial and error, making it the LEGO of coding projects. Who said debugging can't be fun?</p>
</li>
<li><p><strong>Creativity party:</strong> Ever wanted to create a world where gravity works sideways, and cows wear spacesuits? In game development, your creativity runs wild.</p>
</li>
<li><p><strong>Solving mysteries, coding edition:</strong> Games come with puzzles. Not just for players, but for you, the mastermind behind the scenes. Think of it as creating your own coding mystery novel where every bug is a plot twist waiting to be solved.</p>
</li>
<li><p><strong>Learn by playing:</strong> Remember those boring textbooks? Well, forget them. With game development, you're not just reading – you're playing.</p>
</li>
<li><p><strong>Show off your skills:</strong> Building games isn't just about fun. It's about flexing your coding muscles. Your game is your trophy, your badge of honor. Imagine showing up to a job interview with a game you built. Who's cool now?</p>
</li>
</ol>
<p>So, why settle for coding when you can create a universe? Game development is where coding becomes an epic adventure, and you, my friend, are the hero. <strong>Ready to level up?</strong></p>
<p>Alright, let's craft this game together, step by step, and make it a blast! Wondering what it'll look like when it's all done? Check out this snazzy preview:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/image-66.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Preview of what the game will look like, showing an alien spaceship descending to pick up some cows.</em></p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-the-environment">How to Set Up the Environment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-design-the-game-concept">How to Design the Game Concept</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-code-the-game">How to Code the Game</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-how-to-set-up-the-environment">How to Set Up the Environment</h2>
<h3 id="heading-install-pygame">Install PyGame</h3>
<p>Let's kick off this journey by setting up the playground. First, you'll need to install PyGame. Here's a simple guide to get you started.</p>
<h3 id="heading-1-create-a-new-directory">1. Create a new directory</h3>
<p>Open your favorite terminal and navigate to the location where you want to keep your game. Create a new directory for your project. Let's call it "<em>AlienAbductionGame.</em>"</p>
<pre><code class="lang-bash">mkdir AlienAbductionGame
</code></pre>
<h3 id="heading-2-navigate-to-the-project-directory">2. Navigate to the project directory</h3>
<p>Move into your newly created directory.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> AlienAbductionGame
</code></pre>
<h3 id="heading-3-install-pygame">3. Install PyGame</h3>
<pre><code class="lang-bash">pip install pygame
</code></pre>
<p>Great! Now you're armed with PyGame, and you're ready to get into the coding.</p>
<h3 id="heading-what-else-do-you-need-to-start">What else do you need to start?</h3>
<p>You already have Python with PyGame installed on your computer. So, the last thing you need is your favorite code editor. I will use and recommend Visual Studio Code, but you can use any other editor that you like or feel comfortable with.</p>
<p>Once you have everything installed and your editor ready, let's start by understanding the game concept and its mechanics.</p>
<h2 id="heading-how-to-design-the-game-concept">How to Design the Game Concept</h2>
<h3 id="heading-game-idea-alien-abduction-adventure">Game idea: Alien abduction adventure</h3>
<p>Picture this: You're an alien pilot cruising through the cosmos in your trusty UFO. Unfortunately, you're falling behind on your weekly quota of abductions, and the Intergalactic Federation isn't too pleased. To avoid a cosmic penalty, you must abduct various targets on Earth.</p>
<h3 id="heading-mechanics">Mechanics</h3>
<h4 id="heading-abduction-quota-and-levels">Abduction quota and levels:</h4>
<p>At the start of each level, you're given a specific abduction quota. This represents the number of cows you must abduct to progress.</p>
<p>The game consists of ten levels, each with an increasing quota. Completing one level unlocks the next and restart the quota counter.</p>
<h4 id="heading-ufo-controls">UFO Controls:</h4>
<p>Use the arrow keys or your preferred controls to navigate the UFO across the game screen.</p>
<p>Precise movements are crucial for successful abductions. Mastering the controls ensures efficient target acquisition.</p>
<h4 id="heading-targets-adorable-cows">Targets – adorable cows:</h4>
<p>Targets are charming, pixelated cows wandering on the Earth's surface. You'll approach a cow, activate your tractor beam (space bar), and watch the cow dissappear from your screen.</p>
<h4 id="heading-tractor-beam-mechanics">Tractor beam mechanics:</h4>
<p>You'll press the space bar to activate the tractor beam, which extends from your UFO to the ground.</p>
<p>When the beam touches a cow, it triggers the abduction process, and the cow dissappears, increasing your score and abduction quota.</p>
<h4 id="heading-timer-and-urgency">Timer and urgency:</h4>
<p>Each level comes with a countdown timer, adding a sense of urgency to your abductions.</p>
<p>Successfully reaching the abduction quota before the timer hits zero ensures advancement to the next level.</p>
<h3 id="heading-how-to-decide-on-game-elements-spaceship-targets-and-so-on">How to decide on game elements (spaceship, targets, and so on)</h3>
<p>When it comes to selecting your game elements, simplicity is key. The simpler, the better. So, let's take a look at what you'll need to make the game mechanics work.</p>
<ol>
<li><strong>Spaceship (UFO):</strong></li>
</ol>
<ul>
<li><p>Instead of intricate designs, focus on a distinctive UFO sprite, a cute one</p>
</li>
<li><p>Prioritize smooth movements and responsiveness to player controls.</p>
</li>
</ul>
<ol start="2">
<li><strong>Targets (cows):</strong></li>
</ol>
<ul>
<li><p>Opt for a cute cow sprite that aligns with the game's humor.</p>
</li>
<li><p>Consider changing the cow's color when it's abducted – you will code a red bubble signifying abduction.</p>
</li>
</ul>
<ol start="3">
<li><strong>Background and environment:</strong></li>
</ol>
<ul>
<li><p>Maintain a clean and straightforward background, adjusting the color scheme to match the game's progression.</p>
</li>
<li><p>Gradually modify the star color with each level to signify advancement.</p>
</li>
</ul>
<ol start="4">
<li><strong>Tractor beam:</strong></li>
</ol>
<ul>
<li>Ensure the tractor beam is visually distinguishable. You can experiment with a basic, yet effective, plain yellow color.</li>
</ul>
<ol start="5">
<li><strong>Level indicators:</strong></li>
</ol>
<ul>
<li>Implement a simple level indicator displaying the current level. This can be a small section at the corner of the screen.</li>
</ul>
<ol start="6">
<li><strong>Game Over and victory screens:</strong></li>
</ol>
<ul>
<li>Design straightforward screens indicating success or failure. A simple "Game Over" and "You Win" with accompanying text will suffice, like the following one</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/image-64.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Winning screen</em></p>
<h2 id="heading-how-to-code-the-game">How to Code the Game</h2>
<h3 id="heading-walkthrough-of-key-sections-of-the-code">Walkthrough of key sections of the code</h3>
<p>Now that you have a clear concept and understanding of our game mechanics and it's elements, it's time to get into the code. We'll walk through the key sections of the code.</p>
<p>First, let's start by importing the stuff you need to code our game:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pygame
<span class="hljs-keyword">import</span> random
<span class="hljs-keyword">import</span> sys
</code></pre>
<p>In this section, you are importing three modules: <code>pygame</code>, <code>random</code>, and <code>sys</code>.</p>
<ul>
<li><p><strong>pygame:</strong> This is the main library you're using to create the game. It provides functions and tools for handling graphics, user input, and more.</p>
</li>
<li><p><strong>random:</strong> you'll use this module to generate random numbers. This comes in handy when you want things to happen unpredictably, like the initial position of targets.</p>
</li>
<li><p><strong>sys:</strong> This module provides access to some variables used or maintained by the Python interpreter and to functions that interact strongly with the interpreter. You'll use it for handling system events, such as quitting the game when the player closes the window.</p>
</li>
</ul>
<p>So, you're basically gearing up with the tools you need to make the game visually appealing, dynamic, and responsive to player input.</p>
<h3 id="heading-how-to-code-the-start-screen">How to code the start screen</h3>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start_screen</span>(<span class="hljs-params">screen</span>):</span>
    <span class="hljs-comment"># Constants</span>
    WIDTH, HEIGHT = <span class="hljs-number">800</span>, <span class="hljs-number">600</span>
    BLACK = (<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>)
    WHITE = (<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>)
    FONT_SIZE = <span class="hljs-number">30</span>

    <span class="hljs-comment"># Font for displaying the text</span>
    font = pygame.font.Font(<span class="hljs-literal">None</span>, FONT_SIZE)

    <span class="hljs-comment"># Fill the screen with the background color</span>
    screen.fill(BLACK)

    <span class="hljs-comment"># Introduction text</span>
    intro_text = [
        <span class="hljs-string">"Welcome, Alien Abductor!"</span>,
        <span class="hljs-string">"You're behind on your weekly quota of abductions."</span>,
        <span class="hljs-string">"Help the alien catch up by abducting targets on Earth!"</span>,
        <span class="hljs-string">""</span>,
        <span class="hljs-string">"----------------------------------------------------------------------------------------------"</span>,
        <span class="hljs-string">"Move the UFO with ARROWS and"</span>, 
        <span class="hljs-string">"press SPACE to abduct cows with the track bean."</span>,
        <span class="hljs-string">"----------------------------------------------------------------------------------------------"</span>,
        <span class="hljs-string">""</span>,
        <span class="hljs-string">"Press any key to start the game..."</span>,
        <span class="hljs-string">""</span>,
    ]

    <span class="hljs-comment"># Render and display the introduction text</span>
    y_position = HEIGHT // <span class="hljs-number">4</span>
    <span class="hljs-keyword">for</span> line <span class="hljs-keyword">in</span> intro_text:
        text = font.render(line, <span class="hljs-literal">True</span>, WHITE)
        text_rect = text.get_rect(center=(WIDTH // <span class="hljs-number">2</span>, y_position))
        screen.blit(text, text_rect)
        y_position += FONT_SIZE

    pygame.display.flip()

    <span class="hljs-comment"># Wait for a key press to start the game</span>
    wait_for_key()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wait_for_key</span>():</span>
    waiting = <span class="hljs-literal">True</span>
    <span class="hljs-keyword">while</span> waiting:
        <span class="hljs-keyword">for</span> event <span class="hljs-keyword">in</span> pygame.event.get():
            <span class="hljs-keyword">if</span> event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            <span class="hljs-keyword">elif</span> event.type == pygame.KEYDOWN:
                waiting = <span class="hljs-literal">False</span>
</code></pre>
<p><strong>Code explanation:</strong></p>
<ul>
<li><p>The <code>start_screen</code> function takes a <code>screen</code> parameter, which is the Pygame window where you'll display our introduction. It sets up some constants for screen dimensions, colors, and font size.</p>
</li>
<li><p>The screen is filled with a black background.</p>
</li>
<li><p>An introduction text is defined in <code>intro_text</code>, providing a welcome message, instructions, and a prompt to start the game.</p>
</li>
<li><p>Using Pygame's font functionality, the text is rendered and displayed on the screen.</p>
</li>
<li><p>The function then waits for a key press to start the game by calling the <code>wait_for_key</code> function.</p>
</li>
<li><p>The <code>wait_for_key</code> function loops until a key is pressed or the user closes the window. If a key is pressed, the loop exits, and the introduction screen disappears.</p>
</li>
</ul>
<p>So, by now, you should have something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/image-68.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Start screen</em></p>
<h3 id="heading-how-to-build-text-on-the-screen-function">How to build text on the screen function</h3>
<p>Now, let's look at the following block of code:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">show_text_on_screen</span>(<span class="hljs-params">screen, text, font_size, y_position</span>):</span>
    font = pygame.font.Font(<span class="hljs-literal">None</span>, font_size)
    text_render = font.render(text, <span class="hljs-literal">True</span>, (<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>))
    text_rect = text_render.get_rect(center=(WIDTH // <span class="hljs-number">2</span>, y_position))
    screen.blit(text_render, text_rect)
</code></pre>
<p>This code defines a function <code>show_text_on_screen</code> that displays a text message on the Pygame window. Let's break it down:</p>
<ul>
<li>The function takes four parameters:</li>
</ul>
<ol>
<li><p><code>screen</code>: The Pygame window where the text will be displayed</p>
</li>
<li><p><code>text</code>: The message or text string to be displayed.</p>
</li>
<li><p><code>font_size</code>: The size of the font for the text.</p>
</li>
<li><p><code>y_position</code>: The vertical position on the screen where the text will be centered.</p>
</li>
</ol>
<ul>
<li><p>It creates a Pygame font object with the specified size.</p>
</li>
<li><p>Using the font object, it renders the text with white color (<code>(255, 255, 255)</code> represents RGB values for white).</p>
</li>
<li><p>The <code>get_rect</code> method is used to get the rectangular area that encloses the rendered text. The center of this rectangle is set to be at the horizontal center and the specified vertical position.</p>
</li>
<li><p>Finally, the rendered text is blitted (drawn) onto the screen at the specified position.</p>
</li>
<li><p>This function provides a convenient way to display text messages on the screen with a specified font size and vertical position.</p>
</li>
</ul>
<h3 id="heading-how-to-code-the-game-over-screen">How to code the "Game Over" screen</h3>
<p>Now, you will code a game over screen, so keep going and check the next block of code:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">game_over_screen</span>(<span class="hljs-params">screen</span>):</span>
    screen.fill((<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>))  <span class="hljs-comment"># Fill the screen with black</span>
    show_text_on_screen(screen, <span class="hljs-string">"Game Over"</span>, <span class="hljs-number">50</span>, HEIGHT // <span class="hljs-number">3</span>)
    show_text_on_screen(screen, <span class="hljs-string">f"Your final score: <span class="hljs-subst">{score}</span>"</span>, <span class="hljs-number">30</span>, HEIGHT // <span class="hljs-number">2</span>)
    show_text_on_screen(screen, <span class="hljs-string">"Press any key to exit..."</span>, <span class="hljs-number">20</span>, HEIGHT * <span class="hljs-number">2</span> // <span class="hljs-number">3</span>)
    pygame.display.flip()
    wait_for_key()
</code></pre>
<p>Picking apart the game over screen:</p>
<ul>
<li><p><code>screen.fill((0, 0, 0))</code>: Fills the entire Pygame window with a black background.</p>
</li>
<li><p><code>show_text_on_screen(screen, "Game Over", 50, HEIGHT // 3)</code>: Displays the text "Game Over" with a font size of 50, centered vertically at one-third of the screen height.</p>
</li>
<li><p><code>show_text_on_screen(screen, f"Your final score: {score}", 30, HEIGHT // 2)</code>: Displays the player's final score with a font size of 30, centered vertically at half of the screen height.</p>
</li>
<li><p><code>show_text_on_screen(screen, "Press any key to exit...", 20, HEIGHT * 2 // 3)</code>: Displays the instruction to press any key to exit with a font size of 20, centered vertically at two-thirds of the screen height.</p>
</li>
<li><p><code>pygame.display.flip()</code>: Updates the display to show the changes.</p>
</li>
<li><p><code>wait_for_key()</code>: Waits for a key press before proceeding, effectively making the screen stay until the player interacts.</p>
</li>
</ul>
<p>This function is used to show a game over screen with relevant information such as the final score and an exit instruction, something that by now should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/image-67.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Game Over screen</em></p>
<h3 id="heading-you-win-how-to-code-the-victory-screen">You win! How to code the victory screen :)</h3>
<p>And last but not least, you have the victory screen, so let's take a look at the screen code:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">victory_screen</span>(<span class="hljs-params">screen</span>):</span>
    screen.fill((<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>))  <span class="hljs-comment"># Fill the screen with black</span>
    show_text_on_screen(screen, <span class="hljs-string">"Congratulations!"</span>, <span class="hljs-number">50</span>, HEIGHT // <span class="hljs-number">3</span>)
    show_text_on_screen(screen, <span class="hljs-string">f"You've completed all levels with a score of <span class="hljs-subst">{score}</span>"</span>, <span class="hljs-number">30</span>, HEIGHT // <span class="hljs-number">2</span>)
    show_text_on_screen(screen, <span class="hljs-string">"Press any key to exit..."</span>, <span class="hljs-number">20</span>, HEIGHT * <span class="hljs-number">2</span> // <span class="hljs-number">3</span>)
    pygame.display.flip()
    wait_for_key()
</code></pre>
<p>Code explanation:</p>
<ul>
<li><p><code>screen.fill((0, 0, 0))</code>: Fills the entire Pygame window with a black background.</p>
</li>
<li><p><code>show_text_on_screen(screen, "Congratulations!", 50, HEIGHT // 3)</code>: Displays the text "Congratulations!" with a font size of 50, centered vertically at one-third of the screen height.</p>
</li>
<li><p><code>show_text_on_screen(screen, f"You've completed all levels with a score of {score}", 30, HEIGHT // 2)</code>: Displays a congratulatory message with the player's final score and a font size of 30, centered vertically at half of the screen height.</p>
</li>
<li><p><code>show_text_on_screen(screen, "Press any key to exit...", 20, HEIGHT * 2 // 3)</code>: Displays the instruction to press any key to exit with a font size of 20, centered vertically at two-thirds of the screen height.</p>
</li>
<li><p><code>pygame.display.flip()</code>: Updates the display to show the changes.</p>
</li>
<li><p><code>wait_for_key()</code>: Waits for a key press before proceeding, effectively making the screen stay until the player interacts.</p>
</li>
</ul>
<p>This function is used to show a victory screen with a congratulatory message and the player's final score.</p>
<p>So now you have the start of the game, the screens you will use to communicate with the player.</p>
<h3 id="heading-lets-build-some-sprites">Let's build some sprites</h3>
<p>Next up, you will code the base parameters such as the window size, sprites (the UFO and cow), colors, stars, and so on.</p>
<p>Take a look to the following block of code:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Load spaceship and cow images</span>
ovni = pygame.image.load(<span class="hljs-string">"ovni.png"</span>)
cow = pygame.image.load(<span class="hljs-string">"cow.png"</span>)

<span class="hljs-comment"># Resize images if needed</span>
ovni = pygame.transform.scale(ovni, (<span class="hljs-number">50</span>, <span class="hljs-number">50</span>))
cow = pygame.transform.scale(cow, (<span class="hljs-number">40</span>, <span class="hljs-number">40</span>))

<span class="hljs-comment"># Initialize Pygame</span>
pygame.init()

<span class="hljs-comment"># Constants</span>
WIDTH, HEIGHT = <span class="hljs-number">800</span>, <span class="hljs-number">600</span>
FPS = <span class="hljs-number">60</span>
BLACK = (<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>)
WHITE = (<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>)
RED = (<span class="hljs-number">255</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>)
YELLOW = (<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0</span>)
GRAY = (<span class="hljs-number">169</span>, <span class="hljs-number">169</span>, <span class="hljs-number">169</span>)
ORANGE = (<span class="hljs-number">255</span>, <span class="hljs-number">165</span>, <span class="hljs-number">0</span>)
LIGHT_BLUE = (<span class="hljs-number">173</span>, <span class="hljs-number">216</span>, <span class="hljs-number">230</span>)  <span class="hljs-comment"># Light blue color for the level indicator</span>
SHIP_GREEN = (<span class="hljs-number">0</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0</span>)  <span class="hljs-comment"># Green color for the ship</span>
GRASS_GREEN = (<span class="hljs-number">0</span>, <span class="hljs-number">100</span>, <span class="hljs-number">0</span>)  <span class="hljs-comment"># Darker green color for the grass</span>
STAR_COUNT = int(WIDTH * HEIGHT * <span class="hljs-number">0.001</span>)
</code></pre>
<p>Code explanation:</p>
<ul>
<li><p><code>ovni = pygame.image.load("ovni.png")</code> and <code>cow = pygame.image.load("cow.png")</code>: Load the spaceship (ovni) and cow images from files.</p>
</li>
<li><p><code>ovni = pygame.transform.scale(ovni, (50, 50))</code> and <code>cow = pygame.transform.scale(cow, (40, 40))</code>: Resize the images if needed. In this case, the spaceship is resized to a width and height of 50 pixels, and the cow is resized to a width and height of 40 pixels.</p>
</li>
<li><p><code>pygame.init()</code>: Initializes Pygame.</p>
</li>
</ul>
<p>Constants:</p>
<ul>
<li><p><code>WIDTH, HEIGHT = 800, 600</code>: Sets the width and height of the game window.</p>
</li>
<li><p><code>FPS = 60</code>: Sets the frames per second for the game.</p>
</li>
<li><p>Colors: <code>BLACK, WHITE, RED, YELLOW, GRAY, ORANGE</code>: Define color constants using RGB values. <code>LIGHT_BLUE, SHIP_GREEN, GRASS_GREEN</code>: Additional color constants for specific elements.</p>
</li>
<li><p><code>STAR_COUNT</code>: Calculates the number of stars based on the window size.</p>
</li>
</ul>
<p>This section handles the setup of images for the spaceship and cow, adjusting their sizes as needed. It also establishes constants for various aspects of the game.</p>
<p>The subsequent steps involve creating the game window and implementing player controls, collision detection, and other essential elements of the gameplay.</p>
<h3 id="heading-how-to-code-the-game-window-and-set-up-the-fps">How to code the game window and set up the FPS</h3>
<pre><code class="lang-python"><span class="hljs-comment"># Create the game window</span>
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(<span class="hljs-string">"Alien Abduction Game"</span>)

<span class="hljs-comment"># Clock to control the frame rate</span>
clock = pygame.time.Clock()

<span class="hljs-comment"># Player (alien spaceship)</span>
player_rect = pygame.Rect(WIDTH // <span class="hljs-number">2</span> - <span class="hljs-number">25</span>, <span class="hljs-number">10</span>, <span class="hljs-number">50</span>, <span class="hljs-number">50</span>)
player_speed = <span class="hljs-number">5</span>

<span class="hljs-comment"># List to store targets (animals)</span>
targets = []

<span class="hljs-comment"># Set initial score</span>
score = <span class="hljs-number">0</span>

<span class="hljs-comment"># Font for displaying the score, level, and timer</span>
font = pygame.font.Font(<span class="hljs-literal">None</span>, <span class="hljs-number">36</span>)

<span class="hljs-comment"># Flag to track if spacebar is pressed</span>
space_pressed = <span class="hljs-literal">False</span>

<span class="hljs-comment"># List to store stars</span>
stars = [{<span class="hljs-string">'x'</span>: random.randint(<span class="hljs-number">0</span>, WIDTH), <span class="hljs-string">'y'</span>: random.randint(<span class="hljs-number">0</span>, HEIGHT), <span class="hljs-string">'size'</span>: random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">3</span>),
          <span class="hljs-string">'color'</span>: LIGHT_BLUE} <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(STAR_COUNT)]

<span class="hljs-comment"># Grassy area at the bottom</span>
grass_rect = pygame.Rect(<span class="hljs-number">0</span>, HEIGHT - <span class="hljs-number">40</span>, WIDTH, <span class="hljs-number">40</span>)

<span class="hljs-comment"># Level and Countdown Variables</span>
current_level = <span class="hljs-number">1</span>
abduction_target = <span class="hljs-number">10</span>  <span class="hljs-comment"># Initial target</span>
countdown_timer = <span class="hljs-number">60</span>  <span class="hljs-comment"># Initial countdown timer in seconds</span>
current_score = <span class="hljs-number">0</span>  <span class="hljs-comment"># New counter to track the score for the current level</span>

<span class="hljs-comment"># Counter to control the pace of target appearances</span>
target_spawn_counter = <span class="hljs-number">0</span>
TARGET_SPAWN_RATE = max(<span class="hljs-number">30</span>, <span class="hljs-number">120</span> - (current_level * <span class="hljs-number">90</span>))  <span class="hljs-comment"># Adjust the rate based on the current level</span>

<span class="hljs-comment"># List of colors for each level</span>
level_colors = [
    LIGHT_BLUE,
    ORANGE,
    RED,
    YELLOW,
    GRAY,
    (<span class="hljs-number">0</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0</span>),  <span class="hljs-comment"># Green</span>
    (<span class="hljs-number">255</span>, <span class="hljs-number">0</span>, <span class="hljs-number">255</span>),  <span class="hljs-comment"># Purple</span>
    (<span class="hljs-number">0</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>),  <span class="hljs-comment"># Cyan</span>
    (<span class="hljs-number">255</span>, <span class="hljs-number">165</span>, <span class="hljs-number">0</span>),  <span class="hljs-comment"># Orange</span>
    (<span class="hljs-number">128</span>, <span class="hljs-number">0</span>, <span class="hljs-number">128</span>),  <span class="hljs-comment"># Indigo</span>
]
</code></pre>
<p>Code explanation:</p>
<p><strong>Creating the Game Window:</strong></p>
<ul>
<li><p><code>screen = pygame.display.set_mode((WIDTH, HEIGHT))</code>: This line creates the game window with the specified width and height.</p>
</li>
<li><p><code>pygame.display.set_caption("Alien Abduction Game")</code>: Sets the title or caption of the game window.</p>
</li>
</ul>
<p><strong>Clock for Frame Rate:</strong></p>
<ul>
<li><code>clock = pygame.time.Clock()</code>: Initializes a clock object to control the frame rate of the game.</li>
</ul>
<p><strong>Player (Alien Spaceship):</strong></p>
<ul>
<li><p><code>player_rect = pygame.Rect(WIDTH // 2 - 25, 10, 50, 50)</code>: Defines a rectangular area for the player (alien spaceship) at the top center of the window.</p>
</li>
<li><p><code>player_speed = 5</code>: Sets the speed at which the player can move.</p>
</li>
</ul>
<p><strong>Targets (Animals):</strong></p>
<ul>
<li><code>targets = []</code>: Initializes an empty list to store targets (animals).</li>
</ul>
<p><strong>Score:</strong></p>
<ul>
<li><code>score = 0</code>: Initializes the score to zero.</li>
</ul>
<p><strong>Font for Displaying Text:</strong></p>
<ul>
<li><code>font = pygame.font.Font(None, 36)</code>: Creates a font object for displaying score, level, and timer.</li>
</ul>
<p><strong>Spacebar Pressed Flag:</strong></p>
<ul>
<li><code>space_pressed = False</code>: Initializes a flag to track whether the spacebar is pressed.</li>
</ul>
<p><strong>Stars:</strong></p>
<ul>
<li><code>stars = [...]</code>: Creates a list of stars with random positions, sizes, and colors. This is used to create a starry background.</li>
</ul>
<p><strong>Grassy Area at the Bottom:</strong></p>
<ul>
<li><code>grass_rect = pygame.Rect(0, HEIGHT - 40, WIDTH, 40)</code>: Defines a rectangular area at the bottom for a grassy background.</li>
</ul>
<p><strong>Level and Countdown Variables:</strong></p>
<ul>
<li><p><code>current_level = 1</code>: Initializes the game at level 1.</p>
</li>
<li><p><code>abduction_target = 10</code>: Sets the initial abduction target.</p>
</li>
<li><p><code>countdown_timer = 60</code>: Sets the initial countdown timer in seconds.</p>
</li>
<li><p><code>current_score = 0</code>: Initializes a counter to track the score for the current level.</p>
</li>
</ul>
<p><strong>Target Spawn Counter:</strong></p>
<ul>
<li><code>target_spawn_counter = 0</code>: Initializes a counter to control the pace of target appearances.</li>
</ul>
<p><strong>Target Spawn Rate:</strong></p>
<ul>
<li><code>TARGET_SPAWN_RATE = max(30, 120 - (current_level * 90))</code>: Adjusts the rate of target appearance based on the current level.</li>
</ul>
<p><strong>Colors for Each Level:</strong></p>
<ul>
<li><code>level_colors = [...]</code>: Defines a list of colors for each level, which will be used in the game.</li>
</ul>
<p>These variables and settings establish the initial state of the game, defining the player, targets, scoring system, and visual elements. Your game will evolve and respond to player actions based on these initial conditions.</p>
<h3 id="heading-how-to-code-the-game-mechanisms">How to code the game mechanisms</h3>
<p>Take a look at these functions that you will use to run the game. Try to code it yourself before you copy and paste the code. This will help you understand the thinking process between the mechanics and the actual code.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Function to display the start screen</span>
start_screen(screen)

<span class="hljs-comment"># Main game loop</span>
running = <span class="hljs-literal">True</span>
game_started = <span class="hljs-literal">False</span>  <span class="hljs-comment"># Flag to track whether the game has started</span>

<span class="hljs-keyword">while</span> running:
    <span class="hljs-keyword">for</span> event <span class="hljs-keyword">in</span> pygame.event.get():
        <span class="hljs-keyword">if</span> event.type == pygame.QUIT:
            running = <span class="hljs-literal">False</span>
        <span class="hljs-keyword">elif</span> event.type == pygame.KEYDOWN:
            <span class="hljs-keyword">if</span> game_started:
                game_started = <span class="hljs-literal">True</span>  <span class="hljs-comment"># Set the flag to True to avoid calling start_screen repeatedly</span>
                <span class="hljs-keyword">continue</span>  <span class="hljs-comment"># Skip the rest of the loop until the game has started</span>
            <span class="hljs-keyword">elif</span> event.key == pygame.K_SPACE:
                space_pressed = <span class="hljs-literal">True</span>
        <span class="hljs-keyword">elif</span> event.type == pygame.KEYUP <span class="hljs-keyword">and</span> event.key == pygame.K_SPACE:
            space_pressed = <span class="hljs-literal">False</span>

    keys = pygame.key.get_pressed()

    <span class="hljs-comment"># Move the player</span>
    player_rect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * player_speed
    player_rect.y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * player_speed

    <span class="hljs-comment"># Ensure the player stays within the screen boundaries</span>
    player_rect.x = max(<span class="hljs-number">0</span>, min(player_rect.x, WIDTH - player_rect.width))
    player_rect.y = max(<span class="hljs-number">0</span>, min(player_rect.y, HEIGHT - player_rect.height))

    <span class="hljs-comment"># Spawn a new target based on the counter</span>
    target_spawn_counter += <span class="hljs-number">1</span>
    <span class="hljs-keyword">if</span> target_spawn_counter &gt;= TARGET_SPAWN_RATE:
        target_rect = pygame.Rect(random.randint(<span class="hljs-number">0</span>, WIDTH - <span class="hljs-number">20</span>), HEIGHT - <span class="hljs-number">50</span>, <span class="hljs-number">50</span>, <span class="hljs-number">50</span>)
        targets.append(target_rect)
        target_spawn_counter = <span class="hljs-number">0</span>

    <span class="hljs-comment"># Update star glow animation and color for the current level</span>
    <span class="hljs-keyword">for</span> star <span class="hljs-keyword">in</span> stars:
        star[<span class="hljs-string">'size'</span>] += <span class="hljs-number">0.05</span>
        <span class="hljs-keyword">if</span> star[<span class="hljs-string">'size'</span>] &gt; <span class="hljs-number">3</span>:
            star[<span class="hljs-string">'size'</span>] = <span class="hljs-number">1</span>
        star[<span class="hljs-string">'color'</span>] = level_colors[current_level - <span class="hljs-number">1</span>]
</code></pre>
<p>Code explanation:</p>
<p><strong>Display Start Screen:</strong></p>
<ul>
<li><code>start_screen(screen)</code>: Calls the <code>start_screen</code> function to display the initial start screen.</li>
</ul>
<p><strong>Main Game Loop:</strong></p>
<ul>
<li><p><code>running = True</code>: Initializes a flag to control the main game loop.</p>
</li>
<li><p><code>game_started = False</code>: Initializes a flag to track whether the game has started.</p>
</li>
</ul>
<p><strong>Event Handling:</strong></p>
<ul>
<li><p>The loop iterates through pygame events to check for user input and window events.</p>
</li>
<li><p><code>pygame.QUIT</code>: If the user closes the game window, the <code>running</code> flag is set to <code>False</code>, exiting the game.</p>
</li>
<li><p><code>pygame.KEYDOWN</code>: If a key is pressed:</p>
</li>
<li><p>If the game has started (<code>game_started</code> is <code>True</code>), the loop is skipped, preventing repeated calls to the start screen.</p>
</li>
<li><p>If the spacebar (<code>pygame.K_SPACE</code>) is pressed and the game hasn't started, <code>space_pressed</code> is set to <code>True</code>.</p>
</li>
<li><p><code>pygame.KEYUP</code>: If a key is released:</p>
</li>
<li><p>If the released key is the spacebar, <code>space_pressed</code> is set to <code>False</code>.</p>
</li>
</ul>
<p><strong>Player Movement:</strong></p>
<ul>
<li><p>The player's position (<code>player_rect</code>) is updated based on arrow key input.</p>
</li>
<li><p>The player's x-coordinate is adjusted by the difference between the right and left arrow keys multiplied by the player's speed.</p>
</li>
<li><p>The player's y-coordinate is adjusted by the difference between the down and up arrow keys multiplied by the player's speed.</p>
</li>
<li><p>The player's position is constrained to stay within the screen boundaries.</p>
</li>
</ul>
<p><strong>Spawn Targets:</strong></p>
<ul>
<li><p>A counter (<code>target_spawn_counter</code>) is incremented in each iteration.</p>
</li>
<li><p>If the counter exceeds the target spawn rate (<code>TARGET_SPAWN_RATE</code>), a new target is created at a random x-coordinate within the screen width and a fixed y-coordinate above the screen's bottom edge.</p>
</li>
<li><p>The target is represented by a rectangle (<code>target_rect</code>) added to the <code>targets</code> list.</p>
</li>
<li><p>The counter is reset.</p>
</li>
</ul>
<p><strong>Update Star Animation:</strong></p>
<ul>
<li><p>The animation of stars is updated by increasing their size. If the size exceeds 3, it is reset to 1.</p>
</li>
<li><p>The color of each star is set based on the current level.</p>
</li>
</ul>
<p>This part of the code handles user input, player movement, target spawning, and updates the star animation. It's a crucial component of the game loop, ensuring player interaction and progression in the game.</p>
<h3 id="heading-how-to-render-the-elements-of-the-game-player-assets-and-so-on">How to render the elements of the game (player, assets, and so on)</h3>
<p>The next part of the code handles the rendering of game elements on the screen, including stars, the grassy area, the player's spaceship, and targets. It also manages the drawing of the tractor beam and handles collisions between the tractor beam and targets.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Clear the screen</span>
    screen.fill(BLACK)

    <span class="hljs-comment"># Draw stars with level-based color</span>
    <span class="hljs-keyword">for</span> star <span class="hljs-keyword">in</span> stars:
        pygame.draw.circle(screen, star[<span class="hljs-string">'color'</span>], (star[<span class="hljs-string">'x'</span>], star[<span class="hljs-string">'y'</span>]), int(star[<span class="hljs-string">'size'</span>]))

    <span class="hljs-comment"># Draw the grassy area</span>
    pygame.draw.rect(screen, GRASS_GREEN, grass_rect)

    <span class="hljs-comment"># Draw the player and targets</span>
    screen.blit(ovni, player_rect)

    <span class="hljs-keyword">for</span> target <span class="hljs-keyword">in</span> targets:
        screen.blit(cow, target)

    <span class="hljs-comment"># Draw the tractor beam when spacebar is pressed</span>
    <span class="hljs-keyword">if</span> space_pressed:
        tractor_beam_rect = pygame.Rect(player_rect.centerx - <span class="hljs-number">2</span>, player_rect.centery, <span class="hljs-number">4</span>, HEIGHT - player_rect.centery)
        pygame.draw.line(screen, YELLOW, (player_rect.centerx, player_rect.centery),
                         (player_rect.centerx, HEIGHT), <span class="hljs-number">2</span>)

        <span class="hljs-comment"># Check for collisions with targets</span>
        <span class="hljs-keyword">for</span> target <span class="hljs-keyword">in</span> targets[:]:
            <span class="hljs-keyword">if</span> tractor_beam_rect.colliderect(target):
                <span class="hljs-comment"># Change the color of the tractor beam to yellow</span>
                pygame.draw.line(screen, YELLOW, (player_rect.centerx, player_rect.centery),
                                 (player_rect.centerx, target.bottom), <span class="hljs-number">2</span>)
                <span class="hljs-comment"># Change the color of the target to red</span>
                pygame.draw.rect(screen, RED, target)
                targets.remove(target)
                current_score += <span class="hljs-number">1</span>
                score += <span class="hljs-number">1</span>
</code></pre>
<p>Code explanation:</p>
<p><strong>Clear the Screen:</strong></p>
<ul>
<li><code>screen.fill(BLACK)</code>: Fills the entire screen with a black color, effectively clearing the previous frame.</li>
</ul>
<p><strong>Draw Stars:</strong></p>
<ul>
<li><p>Iterates through the list of stars (<code>stars</code>) and draws each star as a circle on the screen.</p>
</li>
<li><p>The circle's color is determined by the star's color attribute, and its position and size are based on the star's x and y coordinates and size.</p>
</li>
</ul>
<p><strong>Draw Grassy Area:</strong></p>
<ul>
<li><code>pygame.draw.rect(screen, GRASS_GREEN, grass_rect)</code>: Draws a rectangle representing the grassy area at the bottom of the screen. The color is set to <code>GRASS_GREEN</code>.</li>
</ul>
<p><strong>Draw Player and Targets:</strong></p>
<ul>
<li><p><code>screen.blit(ovni, player_rect)</code>: Draws the player's spaceship (<code>ovni</code>) on the screen at the position specified by <code>player_rect</code>.</p>
</li>
<li><p><code>for target in targets: screen.blit(cow, target)</code>: Draws each target (cow) from the <code>targets</code> list on the screen at their respective positions.</p>
</li>
</ul>
<p><strong>Draw Tractor Beam (When Spacebar is Pressed):</strong></p>
<ul>
<li><p>Checks if the spacebar is pressed (<code>space_pressed</code> is <code>True</code>).</p>
</li>
<li><p>If true, <code>tractor_beam_rect</code>: Creates a rectangle representing the tractor beam based on the player's position.</p>
</li>
<li><p><code>pygame.draw.line</code>: Draws a yellow line representing the tractor beam from the player's center to the bottom of the screen.</p>
</li>
<li><p>Checks for collisions between the tractor beam and targets.</p>
</li>
<li><p>If a collision is detected, the target is removed, the tractor beam color changes to yellow, and the target's color changes to red.</p>
</li>
<li><p>The score is updated.</p>
</li>
</ul>
<h3 id="heading-game-logic">Game logic</h3>
<p>Now you are almost done – but first you need to add some logic in the game like the countdown timer which gives you one minute per level. You also need to draw like a navbar, a simple one with four elements containing the general score, level indicator, timer and abductions.</p>
<p>Here's how we'll do all that:</p>
<pre><code class="lang-python">info_line_y = <span class="hljs-number">10</span>  <span class="hljs-comment"># Adjust the vertical position as needed</span>
    info_spacing = <span class="hljs-number">75</span>  <span class="hljs-comment"># Adjust the spacing as needed</span>

    <span class="hljs-comment"># Draw the score in an orange rectangle at the top left</span>
    score_text = font.render(<span class="hljs-string">f"Score: <span class="hljs-subst">{score}</span>"</span>, <span class="hljs-literal">True</span>, WHITE)
    score_rect = score_text.get_rect(topleft=(<span class="hljs-number">10</span>, info_line_y))
    pygame.draw.rect(screen, ORANGE, score_rect.inflate(<span class="hljs-number">10</span>, <span class="hljs-number">5</span>))
    screen.blit(score_text, score_rect)

    <span class="hljs-comment"># Draw the level indicator in a light-blue rectangle at the top left (next to the score)</span>
    level_text = font.render(<span class="hljs-string">f"Level: <span class="hljs-subst">{current_level}</span>"</span>, <span class="hljs-literal">True</span>, WHITE)
    level_rect = level_text.get_rect(topleft=(score_rect.topright[<span class="hljs-number">0</span>] + info_spacing, info_line_y))
    pygame.draw.rect(screen, LIGHT_BLUE, level_rect.inflate(<span class="hljs-number">10</span>, <span class="hljs-number">5</span>))
    screen.blit(level_text, level_rect)

    <span class="hljs-comment"># Draw the countdown timer in a red rectangle at the top left (next to the level)</span>
    timer_text = font.render(<span class="hljs-string">f"Time: <span class="hljs-subst">{int(countdown_timer)}</span>"</span>, <span class="hljs-literal">True</span>, WHITE)
    timer_rect = timer_text.get_rect(topleft=(level_rect.topright[<span class="hljs-number">0</span>] + info_spacing, info_line_y))
    pygame.draw.rect(screen, RED, timer_rect.inflate(<span class="hljs-number">10</span>, <span class="hljs-number">5</span>))
    screen.blit(timer_text, timer_rect)

    <span class="hljs-comment"># Draw the targets to acquire for the current level in a gray rectangle at the top left (next to the timer)</span>
    targets_text = font.render(<span class="hljs-string">f"Abductions: <span class="hljs-subst">{current_score}</span>/<span class="hljs-subst">{abduction_target}</span>"</span>, <span class="hljs-literal">True</span>, WHITE)
    targets_rect = targets_text.get_rect(topleft=(timer_rect.topright[<span class="hljs-number">0</span>] + info_spacing, info_line_y))
    pygame.draw.rect(screen, GRAY, targets_rect.inflate(<span class="hljs-number">10</span>, <span class="hljs-number">5</span>))
    screen.blit(targets_text, targets_rect)

    <span class="hljs-comment"># Update the display</span>
    pygame.display.flip()

    <span class="hljs-comment"># Cap the frame rate</span>
    clock.tick(FPS)
</code></pre>
<p>Code explanation:</p>
<p><strong>Info Line Positioning:</strong></p>
<ul>
<li><p><code>info_line_y = 10</code>: Specifies the vertical position for the information line at the top of the screen.</p>
</li>
<li><p><code>info_spacing = 75</code>: Sets the spacing between different pieces of information on the line.</p>
</li>
</ul>
<p><strong>Draw Score:</strong></p>
<ul>
<li><p><code>score_text</code>: Renders the score text using the game font.</p>
</li>
<li><p><code>score_rect</code>: Retrieves the rectangle that encloses the rendered score text.</p>
</li>
<li><p><code>pygame.draw.rect</code>: Draws an orange rectangle around the score text, creating a background.</p>
</li>
<li><p><code>screen.blit(score_text, score_rect)</code>: Blits (renders) the score text onto the screen.</p>
</li>
</ul>
<p><strong>Draw Level Indicator:</strong></p>
<ul>
<li><p><code>level_text</code>: Renders the level indicator text.</p>
</li>
<li><p><code>level_rect</code>: Retrieves the rectangle for the level indicator text.</p>
</li>
<li><p><code>pygame.draw.rect</code>: Draws a light-blue rectangle around the level indicator text.</p>
</li>
<li><p><code>screen.blit(level_text, level_rect)</code>: Blits the level indicator text onto the screen.</p>
</li>
</ul>
<p><strong>Draw Countdown Timer:</strong></p>
<ul>
<li><p><code>timer_text</code>: Renders the countdown timer text.</p>
</li>
<li><p><code>timer_rect</code>: Retrieves the rectangle for the countdown timer text.</p>
</li>
<li><p><code>pygame.draw.rect</code>: Draws a red rectangle around the countdown timer text.</p>
</li>
<li><p><code>screen.blit(timer_text, timer_rect)</code>: Blits the countdown timer text onto the screen.</p>
</li>
</ul>
<p><strong>Draw Abduction Targets:</strong></p>
<ul>
<li><p><code>targets_text</code>: Renders the text indicating the number of abductions required for the current level.</p>
</li>
<li><p><code>targets_rect</code>: Retrieves the rectangle for the abduction targets text.</p>
</li>
<li><p><code>pygame.draw.rect</code>: Draws a gray rectangle around the abduction targets text.</p>
</li>
<li><p><code>screen.blit(targets_text, targets_rect)</code>: Blits the abduction targets text onto the screen.</p>
</li>
</ul>
<p><strong>Update Display:</strong></p>
<ul>
<li><code>pygame.display.flip()</code>: Updates the display to reflect the changes made in this iteration.</li>
</ul>
<p><strong>Frame Rate Cap:</strong></p>
<ul>
<li><code>clock.tick(FPS)</code>: Caps the frame rate to the specified frames per second (<code>FPS</code>). This ensures that the game runs at a consistent speed across different systems.</li>
</ul>
<p>And now we're ready for the last code block. It contains the countdown timer logic that's related to the level progression logic and the abductions reset. This means that you need to restart the abductions made by the player to zero every time you level up, for example:</p>
<ul>
<li><p>Level 1: 0/10 abductions</p>
</li>
<li><p>Level 2: 0/20 abductions</p>
</li>
</ul>
<p>And so on – the maximum abductions quota is 100 abductions in level 10, adding 10 abductions to the required quota for every level.</p>
<h3 id="heading-timer-logic-and-quitting-function">Timer logic and quitting function</h3>
<p>Check out the last block of code:</p>
<pre><code class="lang-python"> <span class="hljs-comment"># Countdown Timer Logic</span>
    countdown_timer -= <span class="hljs-number">1</span> / FPS  <span class="hljs-comment"># Decrease the timer based on the frame rate</span>
    <span class="hljs-keyword">if</span> countdown_timer &lt;= <span class="hljs-number">0</span>:
        <span class="hljs-comment"># Check if the player reached the abduction target for the current level</span>
        <span class="hljs-keyword">if</span> current_score &lt; abduction_target:
            <span class="hljs-comment"># Player didn't reach the abduction target, end the game</span>
            game_over_screen(screen)
            running = <span class="hljs-literal">False</span>
        <span class="hljs-keyword">else</span>:
            <span class="hljs-comment"># Move to the next level</span>
            current_level += <span class="hljs-number">1</span>
            <span class="hljs-keyword">if</span> current_level &lt;= <span class="hljs-number">10</span>:
                current_score = <span class="hljs-number">0</span>
                abduction_target = <span class="hljs-number">10</span> * current_level
                countdown_timer = <span class="hljs-number">60</span>  <span class="hljs-comment"># Reset the countdown timer for the next level</span>
                <span class="hljs-comment"># Reset the targets text for the next level</span>
                targets_text = font.render(<span class="hljs-string">f"Abductions: <span class="hljs-subst">{current_score}</span>/<span class="hljs-subst">{abduction_target}</span>"</span>, <span class="hljs-literal">True</span>, WHITE)
                targets_rect = targets_text.get_rect(topleft=(timer_rect.topright[<span class="hljs-number">0</span>] + info_spacing, info_line_y))

    <span class="hljs-comment"># Check if the player reached the abduction target for the current level</span>
    <span class="hljs-keyword">if</span> current_score &gt;= abduction_target:
        <span class="hljs-comment"># Move to the next level</span>
        current_level += <span class="hljs-number">1</span>
        <span class="hljs-keyword">if</span> current_level &lt;= <span class="hljs-number">10</span>:
            current_score = <span class="hljs-number">0</span>
            abduction_target = <span class="hljs-number">10</span> * current_level
            countdown_timer = <span class="hljs-number">60</span>  <span class="hljs-comment"># Reset the countdown timer for the next level</span>
            <span class="hljs-comment"># Reset the targets text for the next level</span>
            targets_text = font.render(<span class="hljs-string">f"Abductions: <span class="hljs-subst">{current_score}</span>/<span class="hljs-subst">{abduction_target}</span>"</span>, <span class="hljs-literal">True</span>, WHITE)
            targets_rect = targets_text.get_rect(topleft=(timer_rect.topright[<span class="hljs-number">0</span>] + info_spacing, info_line_y))
        <span class="hljs-keyword">else</span>:
            victory_screen(screen)
            running = <span class="hljs-literal">False</span>

<span class="hljs-comment"># Quit Pygame</span>
pygame.quit()
</code></pre>
<p><strong>Countdown Timer Logic:</strong></p>
<ul>
<li><code>countdown_timer -= 1 / FPS</code>: Decreases the countdown timer by the fraction <code>1 / FPS</code>. This adjustment ensures that the timer decreases uniformly based on the frame rate.</li>
</ul>
<p><strong>Check Timer Expiration:</strong></p>
<ul>
<li><code>if countdown_timer &lt;= 0:</code>: Checks if the countdown timer has reached or fallen below zero.</li>
</ul>
<p><strong>Player Didn't Reach Abduction Target:</strong></p>
<ul>
<li><p><code>if current_score &lt; abduction_target:</code>: Checks if the player's current score is less than the abduction target for the current level.</p>
</li>
<li><p><code>game_over_screen(screen)</code>: Calls the function to display the game over screen.</p>
</li>
<li><p><code>running = False</code>: Sets the <code>running</code> flag to <code>False</code>, terminating the game loop.</p>
</li>
</ul>
<p><strong>Move to Next Level:</strong></p>
<ul>
<li><p><code>else:</code>: Executes when the player has reached the abduction target for the current level.</p>
</li>
<li><p><code>current_level += 1</code>: Increments the current level.</p>
</li>
<li><p><code>if current_level &lt;= 10:</code>: Checks if there are more levels to proceed to.</p>
</li>
<li><p><code>current_score = 0</code>: Resets the current score for the next level.</p>
</li>
<li><p><code>abduction_target = 10 * current_level</code>: Sets the abduction target for the next level.</p>
</li>
<li><p><code>countdown_timer = 60</code>: Resets the countdown timer for the next level.</p>
</li>
<li><p>Resets the targets text for the next level.</p>
</li>
<li><p><code>targets_text = font.render(f"Abductions: {current_score}/{abduction_target}", True, WHITE)</code></p>
</li>
<li><p><code>targets_rect = targets_text.get_rect(topleft=(timer_rect.topright[0] + info_spacing, info_line_y))</code></p>
</li>
</ul>
<p><strong>Player Reached Abduction Target for All Levels:</strong></p>
<ul>
<li><p><code>else:</code>: Executes when the player has successfully completed all levels (reached level 10).</p>
</li>
<li><p><code>victory_screen(screen)</code>: Calls the function to display the victory screen.</p>
</li>
<li><p><code>running = False</code>: Sets the <code>running</code> flag to <code>False</code>, terminating the game loop.</p>
</li>
</ul>
<p><strong>Quit Pygame:</strong></p>
<ul>
<li><code>pygame.quit()</code>: Cleans up and quits Pygame after the game loop has ended.</li>
</ul>
<p>Now, you're done and you can run the game by typing this in your shell:</p>
<pre><code class="lang-bash">python aliend_aductions_game.py
</code></pre>
<p>If everything it's ok, you should see the start screen that will let you play after you press any key.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We've covered a lot in this tutorial. You started out by setting up the development environment, installing PyGame, and designing the game concept with simple mechanics.</p>
<p>Then you followed the step-by-step process of coding the game, from initializing the environment to implementing player controls, collisions, and dynamic elements. You learned how to integrate images for the spaceship and cows, creating an engaging visual experience.</p>
<p>The game features various levels, each with its own challenge and a countdown timer, adding an element of urgency. You implemented a scoring system, level progression, and engaging graphics to enhance the player experience.</p>
<h3 id="heading-encouragement-for-further-learning">Encouragement for further learning:</h3>
<p>Congratulations on reaching this point! Game development is a dynamic and rewarding learning path, and there's always more to learn. As you continue, consider delving into more advanced topics such as:</p>
<ol>
<li><p><strong>Advanced graphics:</strong> enhance your game with more detailed graphics, animations, and visual effects.</p>
</li>
<li><p><strong>Sound and music:</strong> integrate sound effects and background music to elevate the gaming experience.</p>
</li>
<li><p><strong>Game physics:</strong> explore realistic movements and interactions within the game world.</p>
</li>
<li><p><strong>Multiplayer functionality:</strong> learn how to implement multiplayer features for a more interactive experience.</p>
</li>
<li><p><strong>Optimization techniques:</strong> dive into optimizing your code and graphics for better performance.</p>
</li>
</ol>
<p>If you reach this point, thanks for reading and I hope you enjoy this post as much as I enjoyed doing it, also you can check the original code of this game and download the assets from here:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/jpromanonet/alien_abduction_game">https://github.com/jpromanonet/alien_abduction_game</a></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Whiteboard App with Python and Tkinter ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, you will learn how to build a simple whiteboard app using Python and Tkinter. Some months ago, I was teaching a Python course. I was struggling to convey certain concepts because it was an online course, and I couldn't use a whitebo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-whiteboard-app/</link>
                <guid isPermaLink="false">66d45f623a8352b6c5a2aa96</guid>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tkinter ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan P. Romano ]]>
                </dc:creator>
                <pubDate>Tue, 07 Nov 2023 22:23:59 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/11/whiteboard_tkinter_python_banner_pic.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, you will learn how to build a simple whiteboard app using Python and Tkinter.</p>
<p>Some months ago, I was teaching a Python course. I was struggling to convey certain concepts because it was an online course, and I couldn't use a whiteboard or even a traditional board. The built-in whiteboard feature in Google Meet was also quite complex to use and share.</p>
<p>So, I decided to search on Google to see if there were any GitHub repositories with whiteboard apps.</p>
<p>I found many such repositories. But after trying a lot of them, I found that the apps were often too complicated for my needs. I wanted something simpler, where I could choose colors and line sizes, and then I could do the drawing myself.</p>
<p>So, what did I do? I decided to code my own app. And for this process, I chose to use Python and Tkinter, the default GUI (Graphics User Interface) toolkit that comes with Python.</p>
<p>The end result?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-10.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>The whiteboard app windows with a white canvas to start drawing and writing and the RGB color picker.</em></p>
<p>So in this tutorial, I'll walk you through the process so you can build it yourself. This will help you sharpen your Python skills and learn about Tkinter, too.</p>
<h2 id="heading-how-to-build-the-apps-functionality">How to Build the app's functionality</h2>
<h3 id="heading-setup-your-development-environment">Setup your development environment</h3>
<p>Building this app is pretty straightforward. You will need the latest Python version installed, which you can download and install from here:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.python.org/">https://www.python.org/</a></div>
<p> </p>
<p>If you're a Linux user, you won't need to install it as it comes with your distro. Also, you need to have a basic understanding of Python and know how to create functions.</p>
<p>After verifying that you already have Python installed on your computer, open Visual Studio Code or your preferred code editor to start writing code.</p>
<h3 id="heading-how-to-build-the-drawing-feature">How to build the drawing feature</h3>
<p>Create a Python file and begin by importing the Tkinter and color chooser modules, like this:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tkinter <span class="hljs-keyword">as</span> tk
<span class="hljs-keyword">from</span> tkinter.colorchooser <span class="hljs-keyword">import</span> askcolor
</code></pre>
<p>After importing Tkinter and the colorchooser module, which will open a modal to select our RGB color combinations, you can begin writing the functions to make this whiteboard work.</p>
<p>First, create a function to start drawing, like this:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start_drawing</span>(<span class="hljs-params">event</span>):</span>
    <span class="hljs-keyword">global</span> is_drawing, prev_x, prev_y
    is_drawing = <span class="hljs-literal">True</span>
    prev_x, prev_y = event.x, event.y
</code></pre>
<p>This code defines a function named <code>start_drawing</code> that is meant to handle the beginning of a drawing action in a graphical user interface (GUI) application.</p>
<p>Let's break down what this function does:</p>
<ol>
<li><p><code>def start_drawing(event):</code>: This line defines a function named <code>start_drawing</code> that takes an <code>event</code> as its parameter. In GUI programming, events are actions or occurrences (like mouse clicks, key presses and so on) that trigger specific functions when they happen.</p>
</li>
<li><p><code>global is_drawing, prev_x, prev_y</code>: This line declares that the variables <code>is_drawing</code>, <code>prev_x</code>, and <code>prev_y</code> are global variables. In Python, global variables are accessible from anywhere in the code and can be modified within functions. This line ensures that these variables are accessible within the function.</p>
</li>
<li><p><code>is_drawing = True</code>: This line sets the <code>is_drawing</code> variable to <code>True</code>. This variable is typically used to indicate whether a drawing action is in progress. By setting it to <code>True</code>, the function signals that a drawing action has started.</p>
</li>
<li><p><code>prev_x, prev_y = event.x, event.y</code>: This line captures the current coordinates of the mouse cursor when the <code>start_drawing</code> function is called. It assigns the <code>x</code> and <code>y</code> coordinates of the mouse cursor at that moment to the <code>prev_x</code> and <code>prev_y</code> variables. These variables are used to track the starting point of the drawing action.</p>
</li>
</ol>
<p>So when this function is called (usually in response to a mouse click event), it sets the <code>is_drawing</code> flag to <code>True</code> to indicate that a drawing action is in progress and records the initial position of the mouse cursor using the <code>prev_x</code> and <code>prev_y</code> variables. These variables are then used in the subsequent drawing actions to connect the starting point with the current cursor position to create a drawing on the canvas.</p>
<p>Now let's keep coding. Next up, we need to write a function to actually draw on the whiteboard, like this:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">draw</span>(<span class="hljs-params">event</span>):</span>
    <span class="hljs-keyword">global</span> is_drawing, prev_x, prev_y
    <span class="hljs-keyword">if</span> is_drawing:
        current_x, current_y = event.x, event.y
        canvas.create_line(prev_x, prev_y, current_x, current_y, fill=drawing_color, width=line_width, capstyle=tk.ROUND, smooth=<span class="hljs-literal">True</span>)
        prev_x, prev_y = current_x, current_y
</code></pre>
<p>A drawing is essentially a combination of points filled with colors, functioning as a vector. To work as a vector, it needs to have a starting and ending point. So after creating a function to start drawing, you'll need a function to stop drawing, like this:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">stop_drawing</span>(<span class="hljs-params">event</span>):</span>
    <span class="hljs-keyword">global</span> is_drawing
    is_drawing = <span class="hljs-literal">False</span>
</code></pre>
<h3 id="heading-how-to-build-the-color-changing-feature">How to build the color changing feature</h3>
<p>Now that you have the primary drawing functionality, the next step is to implement the color-changing function. This is a simple function that calls the <code>askcolor</code> module, which is already part of Tkinter, like this:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">change_pen_color</span>():</span>
    <span class="hljs-keyword">global</span> drawing_color
    color = askcolor()[<span class="hljs-number">1</span>]
    <span class="hljs-keyword">if</span> color:
        drawing_color = color
</code></pre>
<p>For the last functionality, you'll create a function to adjust the line width, allowing you to choose the thickness of your lines. Here's how to implement it:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">change_line_width</span>(<span class="hljs-params">value</span>):</span>
    <span class="hljs-keyword">global</span> line_width
    line_width = int(value)
</code></pre>
<p>Now you've completed the functions. Next, you'll use Tkinter to create the window for your app and buttons for choosing colors, clearing the whiteboard, and selecting your line width.</p>
<h2 id="heading-how-to-build-the-gui">How to Build the GUI</h2>
<p>GUI stands for Graphical User Interface, representing the windows you interact with on your computer, smartphone, tablets, and so on.</p>
<p>When coding a desktop app using Python and Tkinter, you define the size, position, buttons, and any other elements you want for your program. In this case, you need to create the following assets:</p>
<ul>
<li><p>A title for your app.</p>
</li>
<li><p>A white blank canvas for drawing.</p>
</li>
<li><p>A frame to hold the controls of your app in the same line.</p>
</li>
<li><p>A color button.</p>
</li>
<li><p>A clear canvas button to erase all your work and start drawing again.</p>
</li>
<li><p>A slider to select your line width.</p>
</li>
</ul>
<h3 id="heading-how-to-create-your-window">How to create your window</h3>
<p>Start by creating a window with a title and a white canvas:</p>
<pre><code class="lang-python">root = tk.Tk()
root.title(<span class="hljs-string">"Whiteboard App"</span>)

canvas = tk.Canvas(root, bg=<span class="hljs-string">"white"</span>)
canvas.pack(fill=<span class="hljs-string">"both"</span>, expand=<span class="hljs-literal">True</span>)

is_drawing = <span class="hljs-literal">False</span>
drawing_color = <span class="hljs-string">"black"</span>
line_width = <span class="hljs-number">2</span>

root.geometry(<span class="hljs-string">"800x600"</span>)
</code></pre>
<p>Let's break down what each part does:</p>
<ol>
<li><p><code>root = tk.Tk()</code>: This line creates the main application window. It initializes a Tkinter application and assigns it to the variable <code>root</code>. This window serves as the container for all the graphical elements of the whiteboard application.</p>
</li>
<li><p><code>root.title("Whiteboard App")</code>: This sets the title of the application window to "Whiteboard App." The title appears in the title bar of the window and provides a name for the application.</p>
</li>
<li><p><code>canvas = tk.Canvas(root, bg="white")</code>: This line creates a drawing canvas within the main application window. The canvas is a white rectangular area where users can draw. It is initialized with a white background color. The canvas is assigned to the variable <code>canvas</code>.</p>
</li>
<li><p><code>canvas.pack(fill="both", expand=True)</code>: This configures the canvas to fill both the horizontal and vertical space of the application window. It allows the canvas to expand and occupy the entire window.</p>
</li>
<li><p><code>is_drawing = False</code>: This initializes a variable <code>is_drawing</code> to <code>False</code>. It's typically used to track whether the user is currently drawing or not. When the user starts drawing, this variable is set to <code>True</code> to indicate an ongoing drawing action.</p>
</li>
<li><p><code>drawing_color = "black"</code>: This initializes a variable <code>drawing_color</code> to "black." It specifies the color that will be used for drawing on the canvas. You can change this color as needed to draw with different colors with the functions you will add later on this tutorial</p>
</li>
<li><p><code>line_width = 2</code>: This initializes a variable <code>line_width</code> to 2. It specifies the width of the lines or strokes used for drawing. You can adjust this value to change the thickness of the lines.</p>
</li>
<li><p><code>root.geometry("800x600")</code>: This sets the initial size of the application window to 800 pixels in width and 600 pixels in height. It defines the dimensions of the window when it is first displayed but you can resize your window and with it, your canvas space.</p>
</li>
</ol>
<h3 id="heading-how-to-build-your-navbar-and-controls">How to build your navbar and controls</h3>
<p>Next thing you need to do is create a frame to hold the buttons or controls in the same line. This is the most comfortable way to have buttons, and it's kind of a navbar.</p>
<pre><code class="lang-python">controls_frame = tk.Frame(root)
controls_frame.pack(side=<span class="hljs-string">"top"</span>, fill=<span class="hljs-string">"x"</span>)
</code></pre>
<p>Then, create two buttons and give them default fixed positions in your screen, like this:</p>
<pre><code class="lang-python">color_button = tk.Button(controls_frame, text=<span class="hljs-string">"Change Color"</span>, command=change_pen_color)
clear_button = tk.Button(controls_frame, text=<span class="hljs-string">"Clear Canvas"</span>, command=<span class="hljs-keyword">lambda</span>: canvas.delete(<span class="hljs-string">"all"</span>))

color_button.pack(side=<span class="hljs-string">"left"</span>, padx=<span class="hljs-number">5</span>, pady=<span class="hljs-number">5</span>)
clear_button.pack(side=<span class="hljs-string">"left"</span>, padx=<span class="hljs-number">5</span>, pady=<span class="hljs-number">5</span>)
</code></pre>
<p>So, right now, if you run your app you will see something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-14.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>The window of the app with the blank canvas and two buttons, one for changing colors and one to clear the canvas.</em></p>
<p>You already have the two main buttons for your app, one to change colors and one to clear the canvas. The last control you need to create is a slider for the line width function. For that, you will write the following code:</p>
<pre><code class="lang-python">line_width_label = tk.Label(controls_frame, text=<span class="hljs-string">"Line Width:"</span>)
line_width_label.pack(side=<span class="hljs-string">"left"</span>, padx=<span class="hljs-number">5</span>, pady=<span class="hljs-number">5</span>)

line_width_slider = tk.Scale(controls_frame, from_=<span class="hljs-number">1</span>, to=<span class="hljs-number">10</span>, orient=<span class="hljs-string">"horizontal"</span>, command=<span class="hljs-keyword">lambda</span> val: change_line_width(val))
line_width_slider.set(line_width)
line_width_slider.pack(side=<span class="hljs-string">"left"</span>, padx=<span class="hljs-number">5</span>, pady=<span class="hljs-number">5</span>)
</code></pre>
<p>And again, let's recap what is going on here:</p>
<ol>
<li><p><code>line_width_label = tk.Label(controls_frame, text="Line Width:")</code>: This line creates a label widget with the text "Line Width." The label is intended to display text to describe the purpose of the following slider (which controls the line width). It is placed within the <code>controls_frame</code> widget.</p>
</li>
<li><p><code>line_width_label.pack(side="left", padx=5, pady=5)</code>: This line configures the label's placement within the <code>controls_frame</code>.</p>
</li>
<li><p><code>side="left"</code>: This sets the label to be placed on the left side of the <code>controls_frame</code>. It ensures that the label is aligned to the left.</p>
</li>
<li><p><code>padx=5</code>: It adds horizontal padding of 5 pixels around the label, creating some spacing.</p>
</li>
<li><p><code>pady=5</code>: It adds vertical padding of 5 pixels around the label, creating spacing.</p>
</li>
<li><p><code>line_width_slider = tk.Scale(controls_frame, from_=1, to=10, orient="horizontal", command=lambda val: change_line_width(val))</code>: This line creates a horizontal slider widget (Scale widget) that allows the user to select a line width. The slider ranges from a minimum value of 1 (<code>from_=1</code>) to a maximum value of 10 (<code>to=10</code>). The <code>command</code> option is set to call the <code>change_line_width</code> function with the selected value whenever the slider position changes.</p>
</li>
<li><p><code>line_width_slider.set(line_width)</code>: This sets the initial position of the slider to the value stored in the <code>line_width</code> variable, which is initialized earlier in the code. This ensures that the slider starts at the default line width.</p>
</li>
<li><p><code>line_width_slider.pack(side="left", padx=5, pady=5)</code>: This line configures the slider's placement within the <code>controls_frame</code>. It is placed on the left side, and padding is added to create spacing around the slider.</p>
</li>
</ol>
<p>So, if you reach this point, your app should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-15.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-connect-your-features-with-your-gui">How to connect your features with your GUI</h3>
<p>But if you press the buttons or move the slider for line width, it won't work because you still need to bind or "link" the functions you coded at the beginning of this tutorial with the buttons and controls you created.</p>
<p>For that, you're going to write this code:</p>
<pre><code class="lang-python">canvas.bind(<span class="hljs-string">"&lt;Button-1&gt;"</span>, start_drawing)
canvas.bind(<span class="hljs-string">"&lt;B1-Motion&gt;"</span>, draw)
canvas.bind(<span class="hljs-string">"&lt;ButtonRelease-1&gt;"</span>, stop_drawing)

root.mainloop()
</code></pre>
<p>So, a last recap to understand the end of your code:</p>
<ul>
<li><p><code>canvas.bind("&lt;Button-1&gt;", start_drawing)</code>: When the left mouse button is clicked on the canvas, it triggers the <code>start_drawing</code> function.</p>
</li>
<li><p><code>canvas.bind("&lt;B1-Motion&gt;", draw)</code>: While the left mouse button is held down and the mouse is moved on the canvas, it triggers the <code>draw</code> function.</p>
</li>
<li><p><code>canvas.bind("&lt;ButtonRelease-1&gt;", stop_drawing)</code>: When the left mouse button is released (button released event), it triggers the <code>stop_drawing</code> function.</p>
</li>
<li><p>And finally, <code>root.mainloop()</code> starts the main loop of the application, allowing it to respond to user interactions and events.</p>
</li>
</ul>
<h2 id="heading-wrapping-up">Wrapping up</h2>
<p>I hope you enjoyed reading through this tutorial as much as I did writing it, and that the whiteboard helps you in whatever you need to do.</p>
<p>If you want to download the app, you can check it out here:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/jpromanonet/white_board_py">https://github.com/jpromanonet/white_board_py</a></div>
<p> </p>
<p>Until next time! Happy coding and keep coding forward to create a cool portfolio =D</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
