Step-by-Step Project Tutorials Archives - SoftUni Global https://softuni.org/category/project-tutorials/ Learn Programming and Start a Developer Job Fri, 25 Nov 2022 09:16:17 +0000 en-US hourly 1 https://wordpress.org/?v=6.1.3 https://softuni.org/wp-content/uploads/2022/04/cropped-SoftUni-Global-Logo-Square-notext-32x32.png Step-by-Step Project Tutorials Archives - SoftUni Global https://softuni.org/category/project-tutorials/ 32 32 Making A Sliding Puzzle in Java: Step-by-step Guide [Project Tutorials] https://softuni.org/project-tutorials/making-a-sliding-puzzle-in-java/ https://softuni.org/project-tutorials/making-a-sliding-puzzle-in-java/#respond Mon, 17 Oct 2022 13:05:04 +0000 https://softuni.org/?p=23354 In this edition of the Project Tutorial series, we will create a simple sliding puzzle game in Java.

The post Making A Sliding Puzzle in Java: Step-by-step Guide [Project Tutorials] appeared first on SoftUni Global.

]]>

Sliding puzzles are mechanical devices made of blocks of wood or plastic set into a frame as well as simple but addictive computer games that improve your problem-solving skills. The pieces are usually simple shapes or imprinted with colors, patterns, sections of a bigger picture, numbers, or letters.  Sliding puzzles, also known as sliders or sliding-block puzzles, are different from rearrangement puzzles in that the pieces cannot be lifted or removed from the frame. To win, you have to arrange them in a specific pattern by sliding them into certain routes on the board. Each move opens a new path and rearranges the pieces, so you have to plan carefully in order to achieve the end configuration.

Following this tutorial, you will make your own 3×3 sliding puzzle using Java.

Sliding-Puzzle-Gameplay

Note: To create the game, you can use more advanced implementations like arrays and matrices. The method used in this tutorial is simple and targets absolute beginners.
Let’s begin.

Before You Start

For the user interface, you use Swing. Swing is a GUI (Graphical User Interface) widget toolkit for Java. It is built on top of the AWT (Abstract Windowing Toolkit) API. Unlike AWT, Java Swing provides platform-independent and lightweight components.

The javax.swing package provides classes for the Java Swing API such as JButton, JTextField, JLabel, JMenu, etc. You will use the Main method to start the program, but the programming logic will be written in a separate class.

Preparing Variables

Create a new project and give it a descriptive and meaningful name.

Your Main method should look like this:

				
					public class Main {
   public static void main(String[] args){
       new Puzzle();
   }
}
				
			

Right-click on your project folder and create a new Java class – Puzzle. To use the functionalities (methods) of Swing, the class should extend JFrame. To make certain actions happen when you click on the puzzle pieces, you also need an event listener. Make the class implement ActionListener.

				
					import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Puzzle extends JFrame implements ActionListener{
}
				
			

Your puzzle will be 3×3 so you need to declare 9 buttons for each of the puzzle pieces, as well as a shuffle button to rearrange them. You can also implement a counter for the number of clicks the user has performed. To make the counter, you need an integer and a label to visualize the number.

				
					JButton b1,b2,b3,b4,b5,b6,b7,b8,b9,shuffle;
int counter = 0;
JLabel counterLabel;
				
			

Creating Constructor

When you start the game, the first thing you will see is a new game window. Let’s set it up. Because the Puzzle class inherits (extends) from JFrame, it can call JFrame methods like setSize() and add(element).

				
					Puzzle(){
   setSize(400,400);
   setLayout(null);
   setVisible(true);
   setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				
			

It is 400×400 pixels in size (which you can customize to your preference) and will close when you click the X button on the top right.

Next, you need to initialize all the elements.

				
					b1 = new JButton("1");
b2 = new JButton(" ");
b3 = new JButton("3");
b4 = new JButton("4");
b5 = new JButton("5");
b6 = new JButton("6");
b7 = new JButton("7");
b8 = new JButton("8");
b9 = new JButton("2");
shuffle = new JButton("Shuffle!");
counterLabel = new JLabel("Clicks: 0");
				
			

Then add these elements to the window and set proper bounds.

				
					add(b1);add(b2);add(b3);add(b4);add(b5);add(b6);add(b7);add(b8);add(b9); add(shuffle);
Container contentPane = this.getContentPane();
contentPane.add(counterLabel);

b1.setBounds(90,60,50,40);
b2.setBounds(160,60,50,40);
b3.setBounds(230,60,50,40);
b4.setBounds(90,115,50,40);
b5.setBounds(160,115,50,40);
b6.setBounds(230,115,50,40);
b7.setBounds(90,170,50,40);
b8.setBounds(160,170,50,40);
b9.setBounds(230,170,50,40);
shuffle.setBounds(135,245,100,40);
counterLabel.setBounds(145,15,180,40);
				
			

Now run the program. It should look like this:

Sliding-Puzzle

The next step is optional, but it will improve the visual appeal of your game. It involves changing the background color of the puzzle pieces, the font, and the font size. You can select your own or use the ones from this example.

				
					shuffle.setBackground(Color.LIGHT_GRAY);

b1.setBackground(Color.decode("#5adbb5"));
b2.setBackground(Color.decode("#5adbb5"));
b3.setBackground(Color.decode("#5adbb5"));
b4.setBackground(Color.decode("#5adbb5"));
b5.setBackground(Color.decode("#5adbb5"));
b6.setBackground(Color.decode("#5adbb5"));
b7.setBackground(Color.decode("#5adbb5"));
b8.setBackground(Color.decode("#5adbb5"));
b9.setBackground(Color.decode("#5adbb5"));

b1.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 18));
b2.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 18));
b3.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 18));
b4.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 18));
b5.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 18));
b6.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 18));
b7.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 18));
b8.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 18));
b9.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 18));
shuffle.setFont(new Font(Font.DIALOG, Font.PLAIN, 18));
counterLabel.setFont(new Font(Font.DIALOG, Font.PLAIN, 18));

				
			

In the end, you get:

Finally, attach an action listener to every button:

				
					b1.addActionListener(this);
b2.addActionListener(this);
b3.addActionListener(this);
b4.addActionListener(this);
b5.addActionListener(this);
b6.addActionListener(this);
b7.addActionListener(this);
b8.addActionListener(this);
b9.addActionListener(this);
shuffle.addActionListener(this);
}
				
			

And the Puzzle constructor is done.

Adding Action

The Action Listener is a simple event handler with only one method – actionPerformed (ActionEvent e). It is used to define what should happen when a user performs a certain operation. It registers the event of clicking a button, for example. The ActionListener is one for all buttons, so you have to make a separate if statement for each one of them in the actionPerformed method. Let’s start with the Shuffle button.

				
					public void actionPerformed(ActionEvent e){
   if(e.getSource() == shuffle){
       String s = b4.getText();
       b4.setText(b9.getText());
       b9.setText(s);
       s = b1.getText();
       b1.setText(b5.getText());
       b5.setText(s);
       s = b2.getText();
       b2.setText(b7.getText());
       b7.setText(s);
       counter = -1;
       counterLabel.setText("Clicks: 0");
   }
				
			

The logic of moving puzzle pieces is simple: instead of physically moving the pieces around the board, you simply change their text.

				
					if(e.getSource() == b1){
   String s = b1.getText();
   if(b2.getText().equals(" ")){ b2.setText(s); b1.setText(" ");}
   else if(b4.getText().equals(" ")){ b4.setText(s); b1.setText(" ");}
}
				
			

Let’s break the process into a few steps:

  1. Extract the text from the current button;
  2. Determine which of the adjacent buttons has no text;
  3. Substitute the empty text with the extracted one;
  4. Set the text of the current button to an empty string.

Follow this logic for the other pieces as well.

				
					if(e.getSource() == b2){
   String s=b2.getText();
   if(b1.getText().equals(" ")){ b1.setText(s); b2.setText(" ");}
   else if(b3.getText().equals(" ")){ b3.setText(s); b2.setText(" ");}
   else if(b5.getText().equals(" ")){ b5.setText(s); b2.setText(" ");}
}
if(e.getSource() == b3){
   String s=b3.getText();
   if(b2.getText().equals(" ")){ b2.setText(s); b3.setText(" ");}
   else if(b6.getText().equals(" ")){ b6.setText(s); b3.setText(" ");}
}
if(e.getSource() == b4){
   String s=b4.getText();
   if(b1.getText().equals(" ")){ b1.setText(s); b4.setText(" ");}
   else if(b7.getText().equals(" ")){ b7.setText(s); b4.setText(" ");}
   else if(b5.getText().equals(" ")){ b5.setText(s); b4.setText(" ");}
}
if(e.getSource() == b5){
   String s=b5.getText();
   if(b2.getText().equals(" ")){ b2.setText(s); b5.setText(" ");}
   else if(b4.getText().equals(" ")){ b4.setText(s); b5.setText(" ");}
   else if(b6.getText().equals(" ")){ b6.setText(s); b5.setText(" ");}
   else if(b8.getText().equals(" ")){ b8.setText(s); b5.setText(" ");}
}
if(e.getSource() == b6){

   String s=b6.getText();
   if(b9.getText().equals(" ")){ b9.setText(s); b6.setText(" ");}
   else if(b3.getText().equals(" ")){ b3.setText(s); b6.setText(" ");}
   else if(b5.getText().equals(" ")){ b5.setText(s); b6.setText(" ");}

}
if(e.getSource() == b7){
   String s=b7.getText();
   if(b4.getText().equals(" ")){ b4.setText(s); b7.setText(" ");}
   else if(b8.getText().equals(" ")){ b8.setText(s); b7.setText(" ");}

}
if(e.getSource() == b8){
   String s=b8.getText();
   if(b7.getText().equals(" ")){ b7.setText(s); b8.setText(" ");}
   else if(b9.getText().equals(" ")){ b9.setText(s); b8.setText(" ");}
   else if(b5.getText().equals(" ")){ b5.setText(s); b8.setText(" ");}
}

				
			

The last button marks the end of the puzzle, so it should also include a statement that checks whether it has been solved. For that to happen, the pieces must be put in the following order:
1 2 3
4 5 6
7 8 empty

Therefore, the simplest way to verify this order is to check the text on each button.

				
					if(e.getSource() == b9){
   String s=b9.getText();
   if(b6.getText().equals(" ")){ b6.setText(s); b9.setText(" ");}
   else if(b8.getText().equals(" ")){ b8.setText(s); b9.setText(" ");}

   if(b1.getText().equals("1")&&b2.getText().equals("2")&&b3.getText()
           .equals("3")&&b4.getText().equals("4")&&b5.getText().equals("5")
           &&b6.getText().equals("6")&&b7.getText().equals("7")&&b8.getText()
           .equals("8")&&b9.getText().equals(" ")){
       JOptionPane.showMessageDialog(Puzzle.this,"YOU WON!\n" + "You clicked: " + counter + " times.");
   }
}
				
			

You can add a dialog box with a custom message that will pop up when the puzzle is solved. To do that, use the JOptionPane.showMessageDialog() method.

Finally, increase the counter integer and update the label’s text to the new value at the end of the if statements.

				
					counter++;
counterLabel.setText("Clicks: " + counter);
				
			

Your sliding puzzle is ready!

Conclusion

By following this tutorial, you have programmed your own sliding puzzle in Java using simple if statements and some basic functionality of the Swing library. Explore the library’s other features and think of ways to expand your project by adding, for example, a scoreboard, an option to switch between different puzzle sizes, randomization of the shuffle, etc. And don’t forget to upload it to your GitHub profile.

To check out the final code and compare it to yours, click the link below.

If you need any help or advice, leave a comment.

Lesson Topics

In this tutorial we cover the following steps:
  • Preparing Variables
  • Creating Constructor
  • Adding Logic to Action Listener

The post Making A Sliding Puzzle in Java: Step-by-step Guide [Project Tutorials] appeared first on SoftUni Global.

]]>
https://softuni.org/project-tutorials/making-a-sliding-puzzle-in-java/feed/ 0
How To Make A Pong Game in C#: Step-by-step Guide [Project Tutorials] https://softuni.org/project-tutorials/how-to-make-a-pong-game-in-csharp-guide/ https://softuni.org/project-tutorials/how-to-make-a-pong-game-in-csharp-guide/#respond Thu, 01 Sep 2022 14:15:30 +0000 https://softuni.org/?p=23082 In this edition of the Project Tutorial series, we will create a simple Pong game with C#.

The post How To Make A Pong Game in C#: Step-by-step Guide [Project Tutorials] appeared first on SoftUni Global.

]]>

Pong is a two-dimensional sports game that is similar to table tennis. It is one of the earliest video games, first released in 1972. Since then, it has been recreated multiple times in different programming languages. Today, you will learn how to make your own version of the game using simple programming concepts in C#.

Let’s begin.

Creating the Field

First, you need to prepare the field with an upper and a lower border and two rackets. Declare two constants of type int that define the dimensions of the field – fieldWidth and fieldLength. To visualize the upper and the lower border, use the string method Repeat on the fieldTile character variable.

				
					const int fieldLength = 50, fieldWidth = 15;
const char fieldTile = '#';
string line = string.Concat(Enumerable.Repeat(fieldTile, fieldLength));
				
			

Then create the game loop and print the borders on the console. The first line starts from coordinates 0,0 and the second one – 0, fieldWidth(15).

				
					while(true) 
{ 
    Console.SetCursorPosition(0,0);
    Console.WriteLine(line);

    Console.SetCursorPosition(0,fieldWidth);
    Console.WriteLine(line);
}

				
			

Next, make a variable for the rackets’ size – racketLength, for the character used to visualize them – racketTile, and for their positions – leftRacketHeight and rightRacketHeight.

				
					const int racketLength = fieldWidth / 4;
const char racketTile = '|';
            
int leftRacketHeight = 0;
int rightRacketHeight = 0;
				
			

To make the rackets appear on the field,add a for loop in the game loop.

				
					for(int i = 0; i < racketLength; i++)
{
    Console.SetCursorPosition(0, i + 1 + leftRacketHeight);
    Console.WriteLine(racketTile);
    Console.SetCursorPosition(fieldLength - 1, i + 1 + rightRacketHeight);
    Console.WriteLine(racketTile);
}
				
			

Player Movement

Make a loop that will continue until a key is pressed. After the loop, check which key has been pressed using a switch and update the rackets’ positions based on that. Clear the previous positions with another for loop.

				
					while(!Console.KeyAvailable)
{
    
}
           
//Check which key has been pressed
switch(Console.ReadKey().Key)
{
    case ConsoleKey.UpArrow:
    if(rightRacketHeight > 0)
    {
        rightRacketHeight--;
    }
    break;

    case ConsoleKey.DownArrow:
    if(rightRacketHeight < fieldWidth - racketLength - 1)
    {
        rightRacketHeight++;
    }
    break;

    case ConsoleKey.W:
    if(leftRacketHeight > 0)
    {
        leftRacketHeight--;
    }
    break;
    
    case ConsoleKey.S:
    if(leftRacketHeight < fieldWidth - racketLength - 1)
    {
        leftRacketHeight++;
    }
    break;
}

//Clear the rackets’ previous positions
for(int i = 1; i < fieldWidth; i++)             
{
Console.SetCursorPosition(0,i);
Console.WriteLine(" ");
Console.SetCursorPosition(fieldLength - 1,i);
Console.WriteLine(" ");
}
				
			

Adding a Ball

What you need to know about the ball is its coordinates, the character representation on the field, and its direction.

				
					int ballX = fieldLength / 2;
    int ballY = fieldWidth / 2;
    const char ballTile = 'O';

    bool isBallGoingDown = true;
    bool isBallGoingRight = true;
				
			

Let’s go back to the empty while loop that waits for a key to be pressed. It has to update the ball’s position.

				
					while(!Console.KeyAvailable)
{
    Console.SetCursorPosition(ballX, ballY);
    Console.WriteLine(ballTile);
    Thread.Sleep(100); //Adds a timer so that the players have time to react
    
    Console.SetCursorPosition(ballX, ballY);
    Console.WriteLine(" "); //Clears the previous position of the ball
    
    //Update position of the ball
    if(isBallGoingDown)
    {
    ballY++;
    } else
    {
    ballY--;
    }
    if(isBallGoingRight)
    {
    ballX++;
    } else
    {
    ballX--;
    }
}
				
			

However, this code does not limit the movement of the ball to the borders of the field. You need to add more conditions to the same while loop and declare variables to store the players’ points.

				
					int leftPlayerPoints = 0;
int rightPlayerPoints = 0;

				
			
				
					if(ballY == 1 || ballY == fieldWidth - 1)
{
isBallGoingDown = !isBallGoingDown; //Change direction
}

if(ballX == 1)
{
    //Left racket hits the ball and it bounces
   if(ballY >= leftRacketHeight + 1 && ballY <= leftRacketHeight + racketLength) 
   {
       isBallGoingRight = !isBallGoingRight;
   }
   else //Ball goes out of the field; Right player scores
   {
      rightPlayerPoints++;
      ballY = fieldWidth / 2;
      ballX = fieldLength / 2;
      Console.SetCursorPosition(scoreboardX, scoreboardY);
      Console.WriteLine($"{leftPlayerPoints} | {rightPlayerPoints}");
      if(rightPlayerPoints == 10)
      {
          goto outer;
      }
   }
}

if(ballX == fieldLength - 2)
{
    //Right racket hits the ball and it bounces
   if(ballY >= rightRacketHeight + 1 && ballY <= rightRacketHeight + racketLength) 
   {
       isBallGoingRight = !isBallGoingRight;
   }
   else //Ball goes out of the field; Left player scores
   {
      leftPlayerPoints++;
      ballY = fieldWidth / 2;
      ballX = fieldLength / 2;
      Console.SetCursorPosition(scoreboardX, scoreboardY);
      Console.WriteLine($"{leftPlayerPoints} | {rightPlayerPoints}");
      if(leftPlayerPoints == 10)
      {
          goto outer;
      }
       
   }
}
				
			

Scoreboard Visualization

To add a scoreboard, you need variables that store its position.

				
					int scoreboardX = fieldLength / 2 -2;
int scoreboardY = fieldWidth + 1;

				
			

The scoreboard is printed on the console every time a player increases their score. Let’s say the game ends when one of the players reaches 10 points. You need to break out of the game loop with the goto command.

				
					//Left Player
leftPlayerPoints++;
ballY = fieldWidth / 2;
ballX = fieldLength / 2;
Console.SetCursorPosition(scoreboardX, scoreboardY);
Console.WriteLine("${leftPlayerPoints} | {rightPlayerPoints}")

if(leftPlayerPoints == 10)
{
      goto outer;
}

//Right Player
rightPlayerPoints++;
ballY = fieldWidth / 2;
ballX = fieldLength / 2;
Console.SetCursorPosition(scoreboardX, scoreboardY);
Console.WriteLine("${leftPlayerPoints} | {rightPlayerPoints}")
if(rightPlayerPoints == 10)
{
      goto outer;
}

				
			

Outside of the game loop put a marker, clear the console and reset the cursor. Check who the winner is and print the appropriate message.

				
					outer:;
        Console.Clear();
        Console.SetCursorPosition(0,0);
        
        if(rightPlayerPoints == 10)
        {
        Console.WriteLine("Right player won!");
        } 
        else 
        {
        Console.WriteLine("Left player won!");
        }
				
			

If you’ve followed all the steps your project should be finished and working now. You can always adjust the values of the variables. For example, you can make the field bigger or smaller or increase the speed of the ball to make the game more challenging.

To check out the final code and compare it to yours click the link below.

Lesson Topics

In this tutorial we cover the following steps:
  • Creating a Field
  • Implementing Player Movement
  • Adding a Ball
  • Scoreboard Visualization

The post How To Make A Pong Game in C#: Step-by-step Guide [Project Tutorials] appeared first on SoftUni Global.

]]>
https://softuni.org/project-tutorials/how-to-make-a-pong-game-in-csharp-guide/feed/ 0
URL Shortener Project – Adding Views, Layout + CSS Styling [Part 2] https://softuni.org/project-tutorials/url-shortener-project-adding-views-layout-css-styling/ https://softuni.org/project-tutorials/url-shortener-project-adding-views-layout-css-styling/#respond Fri, 18 Feb 2022 06:00:00 +0000 https://softuni.org/?p=12378 In our second part of the URL Shortener series, we continue with developing our project. We will create all the views, CSS, and layout page for the project.

The post URL Shortener Project – Adding Views, Layout + CSS Styling [Part 2] appeared first on SoftUni Global.

]]>

In the second part of the tutorial, we will create the user interface for our web application. This will include all the views, CSS, and the layout page. If you haven’t read our previous blog post, where we created our project, you can do it from here.

We start with building the layout page. It allows us to define a common site template that can be inherited in multiple views to provide a consistent look and feel in multiple pages of an application. The layout view eliminates duplicate coding and enhances development speed and easy maintenance.

  • Inside the views folder, we create a layout.pug.

layout.pug

				
					<!DOCTYPE html>
html(lang='en')
  head
    block head
    link(rel='stylesheet', href='/styles.css')
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  body
    header
      a(href='/') Home
      span  | 
      a(href='/urls') Short URLs
      span  | 
      a(href='/add-url') Add URL

    main
      block content
    
    footer
      div © 2022 - URL Shortener
				
			
  • In the head section, we import the .css file that will include our styling. We will create it later inside the public folder.
  • For the body part, we have a header with the navigation of our application. Each anchor tag will lead us to another route.
  • In the main block is the block content that every time will re-render differently depending on our route.
  • We will create a styles.css in our public folder that we made in our previous part.
 

styles.css

				
					body {
  font-family: Arial, Helvetica, sans-serif;
}

header, footer {
  background:rgb(212, 233, 164);
  padding: 8px;
  border-radius: 3px; 
}

footer {
  margin-top: 15px;
}

main {
  margin-left: 10px;
}


table {
  width: 100%;
  border-collapse: collapse;
  background-color: #f5fff5;
}

table th, table td {
  border: 1px solid #ddd;
}

table th {
  padding: 12px 8px;
  text-align: left;
  background-color: rgb(107, 182, 109);
  color: white;    
}

table td {
  padding: 8px;
  overflow-wrap: anywhere;
}

table tr:nth-child(even) {
  background-color: #dff0de;
}

table tr:hover {
  background-color: rgb(198, 207, 180);
}


form table {
  width: 100%;
  max-width: 600px;
}

form table td:nth-child(1) {
  width: 10%;
  white-space: nowrap;
}

main form input {
  width: 100%;
  min-width: 100px;
  box-sizing: border-box;
}

				
			
  • If we want to add more pages, we need to set up the routes in our controller. As we did in the previous part, we create different functions for each  route. In the mvc-controller.js, we  will expand the functionality with new functions.

mvc-controller.js

				
					function setup(app, data) {
  app.get('/', function(req, res) {
        //  Same as before
  });

  app.get('/urls', function(req, res) {
    let model = { urls: data.urls };
    res.render('urls', model);
  });

  app.get('/add-url', function(req, res) {
    let model = { url: "", code: "newCode" };
    res.render('add-url', model);
  });

  app.post('/add-url', function(req, res) {
    res.redirect('/urls');
  });

}

function date2text(inputDate) {
  let date = inputDate.toISOString().split('.')[0];
  date = date.replace('T', ' ');
  return date;
}

module.exports = { setup };
				
			
  • With the first function, we will get the view with all the URLs. It will be the same as the home view functionality.
  • The second function will load the view for the create page. We will access it with the “/add-urlroute.
  • The next third function will have the same route as the previous but with a different type of request. In the app.get(‘/add-url’, … ) we request the view, but with app.post(‘/add-url, …) we will send data to the server. They are on the same route, but we send different types of requests.
  • We will add a helping function data2text() that will be outside of the setup() function. It will help us later.
  • What we need to do next is to create .pug view. First, we will add the urls.pug inside our views folder. We add the following code inside it:

urls.pug

				
					extends layout.pug

block append head
  title='Short URLs'

block content
  h1 Short URLs
  table
    thead
      tr
        th Original URL
        th Short URL
        th Date Created
        th Visits
    tbody
      each url in urls
        tr
          td 
            a(href=`${url.url}` target="_blank") #{url.url}
          td
            a(href=`${url.shortUrl}` target="_blank") #{url.shortUrl}
          td #{url.dateCreated}
          td #{url.visits}
				
			
  • In this view, we will have an HTML table featuring all the records that we request from the server. They are bound to the urls variable. To access each element separately we need to iterate over the collection with a for-each loop. Each row will be with data for a specific record, and every cell with a value for a specific property of the object.

If we start the project and go to the ‘/urlsroute, this will visualize: 

urls-view

  • In next part we will add the add-url.pug view. We add it inside the views folder.

add-url.pug

				
					extends layout.pug

block append head
  title='Add Short URL'

block content
  h1 Add Short URL
  form(method='POST' action='/add-url')
    table
      tr
        td
          label(for='url') URL: 
        td
          input#url(type='text', name='url', value=`${url}`)
      tr
        td
          label(for='code') Short Code: 
        td
          input#code(type='text', name='code', value=`${code}`)
      tr
        td(colspan="2")
          button(type='submit') Create
				
			
  • In this view, we add a form that is with a POST method, and an action points to ‘/add-url‘. To explain what this does, after pressing the submit button, the server will request the app.post(‘/add-url’, …) function that we have typed inside our mvc-controller.  In the next parts, we will add the functionality that saves the record inside the database.
  • Inside the form, we have two input fields. Inside each field, the user will type the values for the URL he needs to create.
  • In the end, it is important for the button to be of type submit. This will submit the form to the server.

If you have done everything correctly, going to the ‘/add-urls‘ route will display you this page:

add-url-view

After completing all the steps, your project will have a user interface that supports different types of screens. If we go to our two new routes ‘/urls‘, and ‘/add-urls‘ you will access the two new pages that we have added. On the ‘/add-urls‘ route, if you submit the form with the required data, you will send a POST request to the server. In the next parts, we will be able to save this information on the server and display it inside the ‘/urlsroute.

Lesson Topics

In this tutorial we cover the following topics:
  • Building the Layout Template in Pug
  • Adding CSS Styles
  • Implementing the “View Short URLs Table”
  • Styling the Table
  • Implementing the “Add URL” Form
  • CSS Styling for Small Screens

Lesson Slides

The post URL Shortener Project – Adding Views, Layout + CSS Styling [Part 2] appeared first on SoftUni Global.

]]>
https://softuni.org/project-tutorials/url-shortener-project-adding-views-layout-css-styling/feed/ 0
URL Shortener Project – Creating the App Structure [Part 1] https://softuni.org/project-tutorials/url-shortener-project-creating-the-app-structure/ https://softuni.org/project-tutorials/url-shortener-project-creating-the-app-structure/#respond Thu, 10 Feb 2022 06:00:00 +0000 https://softuni.org/?p=12280 In this article of the Project Tutorial series, we will create a simple URL Shortener, using JavaScript, Node.js, Express.js and Pug

The post URL Shortener Project – Creating the App Structure [Part 1] appeared first on SoftUni Global.

]]>

In this tutorial, we will create our URL Shortener using JavaScript. We will be using Expres.JS for creating the server-side web application and Pug as a template engine. This tutorial will be split into several parts, and in each part, we will further develop our project. In the end, we will have a fully working Multi Page Application (MPA).

After we initialize our project, we need to split our code logic into different folders. We create folders for:

  • data
  • controllers
  • views
  • public

In our main directory we have an index.js file that is automatically generated by repl.it. You don’t need to install manually any libraries because they will be added automatically when you start the project.

First, in our index.js we need to add the following code:

 

index.js

				
					const express = require('express');
const app = express();
app.use(express.static('public'))
app.set('view engine', 'pug');

const data = require("./data/app-data");
data.seedSampleData();

const mvcController = require(
  "./controllers/mvc-controller");
mvcController.setup(app, data);

let port = process.argv[2];
if (!port) port = process.env['PORT'];
if (!port) port = 8080;

app.listen(port, () => {
  console.log(`App started. Listening at http://localhost:${port}`);
})
.on('error', function(err) {
  if (err.errno === 'EADDRINUSE')
    console.error(`Port ${port} busy.`);
  else 
    throw err;
});
				
			
  • In the first row, we import the ExpressJS node module. Then we bind it to a constant and use it to make static our public folder. Doing this will allow us to use the public folder from any part of our application.
  • We will also set our view engine to pug. This will render all .pug files we set as views.
  • We define constant named data and invoke the function. seedSampleData() inside it. We will create them later. Every time our project is started this function will be initialized.
  • Our next task is to tell the index.js that our MVC-controller exists and set up it.
  • We set our virtual port for repl.it to 8080, and tell the program to listen to this port.
  • If there is an error, it will be automatically displayed on the server’s console.

app-data.js

				
					let urls = [];

function seedSampleData() {
  urls.length = 0; // cleanup
  urls.push({
    url: "https://softuni.org",
    shortCode: "su",
    dateCreated: new Date("2022-02-19T16:41:56"),
    visits: 86
  });
  urls.push({
    url: "https://nakov.com",
    shortCode: "nak", 
    dateCreated: new Date("2022-02-17T14:41:33"), 
    visits: 160
  });
}

module.exports = {
  urls,
  seedSampleData
};
				
			
  • In our data folder we create an app-data.js file. In it is we create our seed of data. We add an empty array that we fill with the seedSampleData() function.
  • In our function we have 2 different objects {} that we push into the urls array.
  • This is a temporary solution and in our next parts will be changed with a real database.

mvc-controller.js

				
					function setup(app, data) {
  app.get('/', function(req, res) {
    let visitors = 0;
    for (const url of data.urls) {
      console.log(url);
      visitors += url.visits;
    }
    let model = { urls: data.urls, visitors };
    res.render('home', model);
  });
}

module.exports = { setup };
				
			
  • Inside our controller folder we create the  mvc-controller.js file. Inside it, we add the function setup() that receives the app and data
  • When our server recieves a GET request with a URL that equals ‘/’, it will invoke the following function.
  •  We iterate over the collection of data and bind it into the model variable. 
  • Then, we render the following view with the data attached to it. 
  • After we are done, we export the function so that the index.js can run it correctly.

home.pug

				
					h1 URL Shortener
ul
  li Short URLs: <b>#{urls.length}</b>
  li URL visitors: <b>#{visitors}</b>    
				
			
  • Finally, we create our home.pug view inside the views folder. That is the html page that will load when the user goes to the ‘/’ URL, that we defined in our controller.
  • We have an unordered list( ul ), in which we have two rows( li ). The first is for the count of our URLs, and the next is the total sum of all visitors summed from all 2 records.
  • If we want to print the data bound to the variable visitors, we must add hashtag # and braces { } around it so that our compiler knows that this isn’t a regular HTML text.

url-first-part-final-lookAfter completing all the steps you will have a simple working Multi Page Application. If you start your project, you will see that everything that we have done is working correctly. We are using the MVC architecture, and we have split the project into different folders and functions for better understanding. This way  you can clearly see where each part is located. Keep up with our parts and see how our project grows more.

Lesson Topics

In this tutorial we cover the following topics:
  • URL Shortener: App Walkthrough
  • Project Structure
  • Creating the App Structure

Remember that coding is a skill, which should be practiced. To learn to code, you should write code every day for a long time. Watching tutorials is not enough. You should code! 

We would love to hear from you, so leave a comment below saying what topics you would like to see next.

Register now and take your free resources right away! Become a member of the SoftUni Global Community and communicate with other students and mentors and get help for FREE.

After registering, you will get access to thе project code.

Lesson Slides

The post URL Shortener Project – Creating the App Structure [Part 1] appeared first on SoftUni Global.

]]>
https://softuni.org/project-tutorials/url-shortener-project-creating-the-app-structure/feed/ 0
How to Make Our Own Flappy Bird in Unity [Project Tutorials] https://softuni.org/project-tutorials/how-to-make-our-own-flappy-bird-in-unity/ https://softuni.org/project-tutorials/how-to-make-our-own-flappy-bird-in-unity/#respond Tue, 08 Feb 2022 04:58:00 +0000 https://softuni.org/?p=11648 In this article of the Project Tutorial series, we will create a simple Flappy Bird game, using Unity.

The post How to Make Our Own Flappy Bird in Unity [Project Tutorials] appeared first on SoftUni Global.

]]>

In this demo, we will create our own Flappy Bird game using Unity and C#.

  • Unity is, essentially, a well-rounded game engine that truly does simplify game development. While there may be better engines to choose from, learning Unity will only help you grow as a game developer.

For this project, we are using the 2020.3 LTS table release. To create this project you will need to have Unity and Unity Hub installed. You can download them from here. To get the completed project, you can download it from the link below. (Link is available after successful registration)

  • First, we open the Unity Hub and Create a 2D Project.setup-path

  • We create a Sprites folder in the game directory, and we import all the needed images for the game.

  • After we import the needed images, you can see that you have more than one bird. We slice it save it in a new folder called Animations.
  • We set it on the scheme, we can start the application and see if the bird will fall.
  • What we need to do next is create a script for our bird. We create a Bird.cs file in the Assets/Scripts folder. We create methods for the Bird to fly and set boundaries so it cannot fly outside our screen.
				
					using System;
using UnityEngine;

public class Bird : MonoBehaviour
{
    [SerializeField] private Rigidbody2D _rigidbody;
    [SerializeField] private float _force;
    [SerializeField] private float _yBound;

    private void Update()
    {
        if (Input.GetMouseButtonDown(0) && _rigidbody.position.y < _yBound)
        {
            Flap();
        }
    }

    private void Flap()
    {
        _rigidbody.velocity = Vector2.zero;
        _rigidbody.AddForce(Vector2.up * _force);
    }
}

				
			
  • Now we need to create pipes. We create Upper and Lower pipes. If the bird hits them the game will be over.
  • After we are done we create a MovingObject infinity runner. We need to constantly move the objects to the left. The speed increased by one, for every second that passes. We set boundaries for when the object is destroyed. We attach the script to the pipe. We can check if our scripts work.
				
					using UnityEngine;

public class MovingObject : MonoBehaviour
{
    [SerializeField] private float _speed;
    [SerializeField] private float _xBound;

    private void Update()
    {
        this.transform.position -= Vector3.right * _speed * Time.deltaTime;

        if (this.transform.position.x < _xBound)
        {
            Destroy(this.gameObject);
        }
    }
}
				
			
  • We can move to the spawner script. We create the class in the same scripts folder. We need a prefab to be spawned, and a time interval arrange by 1 axis with a name – _yClamp. If enough time has elapsed, the object will spawn, and the elapsed time will reset.
				
					using System;
using UnityEngine;

public class Spawner : MonoBehaviour
{
    [SerializeField] private GameObject _prefab;
    [SerializeField] private float _time;
    [SerializeField] private float _yClamp;

    private float _elapsedTime;

    private void Update()
    {
        _elapsedTime += Time.deltaTime;

        if (_elapsedTime > _time)
        {
            SpawnObject();

            _elapsedTime = 0f;
        }
    }

    private void SpawnObject()
    {
        float offsetY = UnityEngine.Random.Range(-_yClamp, _yClamp);

        Vector2 pos = new Vector2(this.transform.position.x, this.transform.position.y + offsetY);

        Instantiate(_prefab, pos, Quaternion.identity, this.transform);
    }
}

				
			
  • After we are done we can put the spawner into action.  We create a spawner to spawn pipes, evey 2 seconds in the y-axis.
  • We add the functionality to the ground as well. If we hit play we can see the pipes and ground spawning infinitely.
  • In our next step, we need to make the game end. We add events to the Bird inside the Bird.cs class. As a bonus you can add sounds for different events. With OnCollisionEnter2D, our bird dies and we freeze the time.
				
					    [SerializeField] private AudioSource _audioSource;
    [SerializeField] private AudioClip _flapSound;
    [SerializeField] private AudioClip _hitSound;
    [SerializeField] private AudioClip _scoreSound;
    public static event Action OnDeath;

    private void OnCollisionEnter2D()
    {
        OnDeath?.Invoke();

        _audioSource.PlayOneShot(_hitSound);

        Time.timeScale = 0f;
    }
    
    private void Start()
    {
        Time.timeScale = 1f;
    }

				
			
  • We need to create a button,  which starts our game.

  • We use the Observer Design Pattern and it’s commonly used in game development.
  • We create a new class called UIManager. In our class we add the following play button logic:

				
					    [SerializeField] private GameObject _playButton;
    [SerializeField] private TMP_Text _score;

    private void Awake()
    {
        Bird.OnDeath += OnGameOver;
    }
    
    
    private void OnDestroy()
    {
        Bird.OnDeath -= OnGameOver;
    }

    public void RestartGame() => SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);

    private void OnGameOver() => _playButton.SetActive(true);


				
			
  • What we need to do is create a text mesh for the score on our screen. In the Bird class, we add functionality so that the score will change. The OnTrigger event will trigger and play a sound.
				
					public static event Action OnScore;

    private void OnTriggerEnter2D()
    {
        OnScore?.Invoke();

        _audioSource.PlayOneShot(_scoreSound);
    }
				
			
  • In the UI Manager we also need to add the functionality for the score. Each time the bird passes a pipe depending on the state we will get Awake() or OnDestroy() event. We increment the current number of the score when the score increases.
				
					private void Awake()
{
    Bird.OnDeath += OnGameOver;
    Bird.OnScore += OnScore;
}
    
private void OnDestroy()
{
    Bird.OnDeath -= OnGameOver;
    Bird.OnScore -= OnScore;
}
private void OnScore() => _score.text = (int.Parse(_score.text) + 1).ToString();
				
			

final-look-app

If we followed all the steps as shown in the video tutorial, our project should be working. What you learned in this tutorial will work for most of your projects in any engine. Unity‘s pipeline is smooth, yet complex. Unity is, simply put, the world’s most popular game engine. It packs a lot of features together and is flexible enough to make almost any game you can imagine. Unity packs tools for 2D and 3D game development.

Lesson Topics

In this tutorial we cover the following steps:
  • Project Creation
  • Project Setup
  • Creating a Bird
  • Adding the Bird Script
  • Prefabs
  • Adding Moving Object
  • Defining Spawner
  • Setup Spawners Usage
  • Implementing Game Over Feature
  • Adding Score
  • Adding SFX
  • Testing Project

The post How to Make Our Own Flappy Bird in Unity [Project Tutorials] appeared first on SoftUni Global.

]]>
https://softuni.org/project-tutorials/how-to-make-our-own-flappy-bird-in-unity/feed/ 0