Typolino – Adding Features (one year later)

Coming back to a side project after a year can be pretty painful. I actually wanted to see how it goes with Typolino. Is the CI/CD pipeline still working? Can I easily upgrade my dependencies and add new features?

A product should grow with your clients and Typolino is no different. My kids get older and they want some new challenges. 🙂

CI/CD

Besides allowing teams to focus on writing code adding business value, having a CI/CD pipeline is also great to come back to an abandoned project. I didn’t have to do anything, it still works fine. I recently tend to tell my colleagues that we should think CI/CD first (like mobile first, API first, …) and I believe this pays off very quickly. I’m aware this can also go wrong, but I was lucky enough. Having a regular run to prove your build still works fine may be a good idea, so that you an fix issues right away.

Upgrade

Upgrading npm dependencies is always a bit cumbersome, especially if you want to use the latest major versions. There is still a lot of movement in the web area. I thought it would be cool to see how I can upgrade a pretty old Angular version to Angular 12. It worked quite well, but it was not painless. To be honest I think this should be easier, it is not something you want to think about too much about, specifically if it affects the build system itself. I didn’t have any breaking API changes, but the build system was updated. It took me more than an hour of absolutely not-fun work. 🙂

As a side note: the Angular team decided to go “prod build by default”. Which now kind of killed the faster development builds, I need to do some more research on how to get this back, but waiting like 20 seconds to see the changes during development is a no go. I’m sure I can fix it, just a question how many extra config in angular.json it will require.

Features

Having the CI/CD still working and the upgrade done I got enough time to add some features.

  • Better styling, I added an Angular component that can render words as keyboard keys. Looks a bit fancier now
  • Updated the colors to be a bit sharper
  • Added a hard mode, that will blank a letter in the word. This is great for my older one as he now needs to know how to properly write the word

Conclusion

Having a proper CI/CD pipeline frees me up from manual activities that would probably hold be back from additional changes in “legacy” code and lets me focus on adding actual value. The hurdles are so much lower in my view.

If you want to test the new features, visit Typolino (still German, sorry).

Develop a game with p5.js (part 3)

In this third and last part of the series on how to develop a game with p5.js we will implement the actual game logic: eat enemies, get bigger and faster and game over handling. You will find the full code at the end of the article and you can play the game here.

New state

First of all let’s add the missing variables to complete our game.

  • We will add a boolean variable to store the information whether the game has ended.
  • As we want our player to get faster and faster with every bite, we need a variable to store the current player’s velocity
let direction = null;
let velocity = 1;
let gameOver = false;

Eating enemies / collision detection

This is the hardest part. But when we move our player around we need a way to find out whether we catched an enemy. Touching the enemy is good enough in our game, so we will need some sort of collision detection!

As all our game objects are circles, the circle collision detection is our best friend. It is pretty easy to understand and also easy to code. But it requires some understanding of the Pythagoras theorem (find the distance between two points). You can read this great article here for a detailed explanation.

In short we first find out the distance of two points using the Pythagoras theorem and then check if we we meet the condition for a collision.

I tried to visualize this here, so if the circles get closer and closer, the distance gets smaller. Once the distance is smaller than the sum of the two radiuses, we have a collision.

Let’s now add this to our game!

distance=\sqrt{(distanceX^2)+(distanceY^2)}

Which can be written in JavaScript using the built in functions sqrt and pow.

  let distance = sqrt(pow(playerPositionX -enemyPositionX ,2) + pow(playerPositionY - enemyPositionY, 2));

Now that we have the distance, we can check for collision, this is simple:

let radii = 10 + playerWeight / 2;
let collisionDetected = distance <= radii;

The radii variable may be a bit surprising: this is just adding up the radius of the player and the enemy. The circle function accepts the diameter, we have a diameter of 20 for the enemy (we should use a constant for this..) the diameter of the player is equal to it’s weight we take 10 for the enemy and half the weight for the player.

Now that we know that we have a collision, we need to update the variables to reflect the new reality. We want to make everything faster, bigger and find a new position for the enemy.

if (collisionDetected) {
    playerWeight += 2;
    velocity += 1;
    enemyPositionX = random(500);
    enemyPositionY = random(500);
}

Where to put the code? We can simply add it to the draw function. As we know, it is called repeatedly.

function draw() {
  
  // get distance of the two circles using Pythagoras
  let distance = sqrt(pow(playerPositionX -enemyPositionX ,2) + pow(playerPositionY - enemyPositionY, 2));
  // get the sum of the two radii (note we pass the diameter to the circle function, so we need to half it!)
  let radii = 10 + playerWeight / 2;
  // check if the distance is smaller than the sum
  let collisionDetected = distance <= radii;
  
  if (collisionDetected) {
    playerWeight += 2;
    velocity += 1;
    enemyPositionX = random(500);
    enemyPositionY = random(500);
  }
  ... rest of the function 

Almost done

You can play around with the updates to the game world. Why not make it even faster, or add way more weight each time you eat an enemy? I found the configuration above to be quite challenging, but still playable.

But one thing is missing: if we hit the border of the playfield, we need to stop the game. In addition we want to print the current weight somewhere on the screen so that we can compare highscores with our friends!

Print the Score

p5.js comes with a handy function to draw text, we just use that one. We can do this as the last thing in our draw function:

  // current score
  fill(60,200,120);
  textSize(20);
  text("your current weight " + playerWeight + " kg",20,20);
}

Hit a Wall

This is another part where we need some sort of collision detection. If we touch the left, right, bottom or top edge the game is over.

// Hit a wall?
  if (playerPositionX < 0 || playerPositionX > 500 || playerPositionY < 0 || playerPositionY > 500) {
   gameOver = true; 
  }

And last but not least, we need to stop the game:

// Game over?
if (gameOver) {
  fill(200,50,40);
  textSize(20);
  text("GAME OVER", 200,250); 
  return; // just skip everything else
}

The End

We created a very simple game with just a few lines of code. I really like p5.js and their editor. My highscore:

What is yours? 😉

Full Code

let playerWeight = 10;
let playerPositionX = 300;
let playerPositionY = 300;
let enemyPositionX = 0;
let enemyPositionY = 0;
let direction = null;
let velocity = 1;
let gameOver = false;

function setup() {
  // setup the random initial location of the enemy
  enemyPositionX = random(500);
  enemyPositionY = random(500);
  createCanvas(500, 500);
}

function draw() {
  // Game over?
  if (gameOver) {
    fill(200,50,40);
    textSize(20);
    text("GAME OVER", 200,250); 
    return; // just skip everything else
  }
  
  // Hit a wall?
  if (playerPositionX < 0 || playerPositionX > 500 || playerPositionY < 0 || playerPositionY > 500) {
   gameOver = true; 
  }
  
  // get distance of the two circles using Pythagoras
  let distance = sqrt(pow(playerPositionX -enemyPositionX ,2) + pow(playerPositionY - enemyPositionY, 2));
  // get the sum of the two radii (note we pass the diameter to the circle function, so we need to half it!)
  let radii = 10 + playerWeight / 2;
  // check if the distance is smaller than the sum
  let collisionDetected = distance <= radii;
  
  if (collisionDetected) {
    playerWeight += 2;
    velocity += 1;
    enemyPositionX = random(500);
    enemyPositionY = random(500);
  }
  
  // Update the world
  if (direction == 'up') {
    playerPositionY = playerPositionY - velocity; 
  }
  if (direction == 'left') {
    playerPositionX = playerPositionX - velocity; 
  }
  if (direction == 'right') {
    playerPositionX = playerPositionX + velocity; 
  }
  if (direction == 'down') {
    playerPositionY = playerPositionY + velocity; 
  }
  
  // draw a black background
  background(0);

  // define the fill color for the player
  fill(255, 120, 90);
  // draw a circle (our player)
  circle(playerPositionX, playerPositionY, playerWeight);

  // define the fill color of the enemy
  fill(0, 255, 0);
  // draw the enemy as a circle
  circle(enemyPositionX, enemyPositionY, 20);
  
  // current score
  fill(60,200,120);
  textSize(20);
  text("your current weight " + playerWeight + " kg",20,20);
}

function keyPressed() {
  if (key == 'w') {
    direction = 'up';
  }
  if (key == 'a') {
    direction = 'left';
  }
  if (key == 's') {
    direction = 'down';
  }
  if (key == 'd') {
    direction = 'right';
  }
}

Develop a game with p5.js (part 2)

Welcome back to the second part on how to develop a game with p5.js. Today we are going to add some interactions to our game. Wouldn’t be a real game if we couldn’t move around something, right?

Now that we already have setup most variables that we need and the scene is set, the rest comes quite easy.

keyPressed()

We just need to add a third function to our code which listens to keyboard input. Whenever some key is pressed that we are interested in, we keep the information in a variable so that we can use that to update our game world.

In other words:

  • if we press “W”, we want to move up
  • if we press “S” we want to move down
  • if we press “A” we want to move left
  • if we press “D” we want to move right

First we add a new variable to our little application:

let enemyPositionX = 0;
let enemyPositionY = 0;
let direction = null;

And then we add our keyboard listener code:

function keyPressed() {
  if (key == 'w') {
    direction = 'up';
  }
  if (key == 'a') {
    direction = 'left';
  }
  if (key == 's') {
    direction = 'down';
  }
  if (key == 'd') {
    direction = 'right';
  }
}

With this we now basically have all the information we need. Now it’s time to move something on the screen!

Image result for excited meme

It may seem a bit weird what we are going to do now, but just think of the keyboard event handler that we just wrote to be completely independent of the draw function. Remember, the draw function is called over and over again automatically by p5.js. So the missing part is to interpret the direction we just got and start moving the player!

function draw() {
  
  // Update the world
  if (direction == 'up') {
    playerPositionY = playerPositionY - 1; 
  }
  if (direction == 'left') {
    playerPositionX = playerPositionX - 1; 
  }
  if (direction == 'right') {
    playerPositionX = playerPositionX + 1; 
  }
  if (direction == 'down') {
    playerPositionY = playerPositionY + 1; 
  }

What we are doing here is pretty simple:

  • every time p5.js runs our draw function we look at the choosen direction and move the player by one pixel
  • This happens by updating the global variable which stores the current player’s location.
  • Then the render logic we wrote in part 1 comes into play (clearing background, drawing player, drawing enemy)
  • You can make the player faster by increasing the amount of pixels it moves per update.

Code

Find the complete running code for your reference

let playerWeight = 10;
let playerPositionX = 300;
let playerPositionY = 300;
let enemyPositionX = 0;
let enemyPositionY = 0;
let direction = null;

function setup() {
  // setup the random initial location of the enemy
  enemyPositionX = random(500);
  enemyPositionY = random(500);
  createCanvas(500, 500);
}

function draw() {
  
  // Update the world
  if (direction == 'up') {
    playerPositionY = playerPositionY - 1; 
  }
  if (direction == 'left') {
    playerPositionX = playerPositionX - 1; 
  }
  if (direction == 'right') {
    playerPositionX = playerPositionX + 1; 
  }
  if (direction == 'down') {
    playerPositionY = playerPositionY + 1; 
  }
  
  // draw a black background
  background(0);

  // define the fill color for the player
  fill(255, 120, 90);
  // draw a circle (our player)
  circle(playerPositionX, playerPositionY, playerWeight);

  // define the fill color of the enemy
  fill(0, 255, 0);
  // draw the enemy as a circle
  circle(enemyPositionX, enemyPositionY, 20);
}

function keyPressed() {
  if (key == 'w') {
    direction = 'up';
  }
  if (key == 'a') {
    direction = 'left';
  }
  if (key == 's') {
    direction = 'down';
  }
  if (key == 'd') {
    direction = 'right';
  }
}

Develop a game with p5.js (part 1)

p5.js is a great JavaScript library to create little games that run directly in your browser. They even offer an online editor, so you can really just get started.

Find out more about p5.js here: https://p5js.org/
Or directly access the online editor: https://editor.p5js.org/

In this article I will show you a game we implemented as part of a programmer training for kids. Let’s go through it step by step!

Image result for im ready meme

Editor

Before we write one line of code I’d like to give you a quick introcution on the editor. Just open https://editor.p5js.org/ and the editor will open up instantly in your favorite browser.

You can write code on the left side and see the result on the right side, it’s that easy. if you hit the *play* button on the top bar it will actually execute the code. If you hit the button without any modification, it will render a grey 400px by 400px square in the preview area on the right side.

Maybe you want to create an account or login via Github or Google. This way you can save your game / application / sketch online.

Canvas

Before we can draw anything on the screen at the location we actually want, we need to understand the canvas and the coordinate system a bit better. Imagine the canvas as a squared paper, each square representing a single pixel. If I would ask you to draw a rect of 3 squares width and 4 squares height on the top left corner, that would be pretty easy.

In the end p5.js works the same way but you just code your instructions and p5.js executes them.

  • First we create our canvas (e.g. createCanvas(400,400)
  • And then we tell p5j.s to draw something on it
function draw() {
  background(220);
  rect(0,0,30,40);
}

In the example above we are now drawing a rectangle beginning at the top left corner. Play around with these numbers to get familiar with the coordinate system. What would you need to do to render a square exactly in the middle of the canvas?

Let’s have a look at the rect() function, it takes several parameters, but we will focus only on the most important ones for now: where do we want to place the rectangle, and what is it’s dimension.

rect(x, y, w, h)

xThe X coordinate of the rect, from left to right, at which point do we want to start drawing the rect
y
The Y coordinate of the rect, from top to bottom, at which point do we want to start drawing the rect
wThe width of the rectangle in pixels
hThe height of the rectangle in pixels

See https://p5js.org/reference/#/p5/rect to learn more about the rect() function. The documentation is fantastic and provides good examples.

Let’s assume our canvas is 400 by 400 pixels and we want to draw a rectangle of 50 by 50 pixels – perfectly centered.

Our first impulse might be to write: rect(200 ,200 ,50 ,50);

Not so bad, but if we really want to center the rect we need to correct the x and y parameters slightly (basically moving our rectangle a 25px left and up). Now we get the result we wanted!

The Game

What is the game about? You are a hungry little ball that want’s to eat other balls. Whenever you eat a new ball you not only get heavier but also faster. Caution: if you leave the playfield, you loose!

We will divide the game programming into three different parts:

  1. setup the scene (rendering the player and the enemy
  2. keyboard support and moving our player
  3. collision detection and finalization

Setup the Scene

State

Our game will need some state. In our simple game we will use some global variables as our state. For example we might want to store the player’s location on the screen, so that we can later update it and render it. Altough later on we will add a bit more state, to get started we need the following state:

playerPositionX
The x coordinate of the player
playerPositionY
The y coordinate of the player
playerWeight The current weight of the player
enemyPositionX The x coordinate of the enemy
enemyPositionY The y coordinate of the player

As you can see the new sketch already contains two function where we can put our code:

setup()

The setup function is used to initialize our game. Here will setup our canvas (on which we will paint our game) and initialize some game variables like the player’s initial position on the screen. When we start the game, this function is called first.

draw()

The draw function is repeatadly invoked by p5.js to render the current state. So here we will actually draw our scene / the current state to the canvas.

Code

let playerWeight  = 10;
let playerPositionX = 300;
let playerPositionY = 300;
let enemyPositionX  = 0;
let enemyPositionY   = 0;
function setup() {
  // setup the random initial location of the enemy
  enemyPositionX  = random(500);
  enemyPositionY   = random(500);
  createCanvas(500, 500);
}

function draw() {
  // draw a black background
  background(0);
  
  // define the fill color for the player
  fill(255,120,90);
  // draw a circle (our player)
  circle(playerPositionX, playerPositionY, playerWeight);
  
  // define the fill color of the enemy
  fill(0,255,0);
  // draw the enemy as a circle
  circle(enemyPositionX , enemyPositionY  , 20);
}

Run the code and you should see something like below in the preview area.

  • We used the setup() function to initialize our canvas and set the initial location of our enemy. random(500) produces a random value between 0 and 500
  • In the draw() function we tell p5.js line by line what do do!
  • First draw a black background. You can actually pass more values to the function to define the color. Maybe try background(255, 0, 0) and you will get a red background. You can actually mix your own color by defining how much red green and blue (RGB) you want in your color. Learn more about the RGB colors; https://www.w3schools.com/colors/colors_rgb.asp
  • Then we ask p5.js to use another fill for its pen (again we can set any RGB color code)
  • After having set the color, we draw a circle at the given location. The third parameter is the diameter
  • Same thing for the enemy, first use another fill color
  • Then draw the circle at the enemy’s location

JavaScript und Physik

Gerade kĂŒrzlich ist mir die Formelsammlung der Physik in die HĂ€nde gefallen und ich hatte irgendwie Lust, ein Pendel zu programmieren. Ich habe frĂŒher bereits einen Artikel geschrieben, wie man mit JavaScript physikalische “Experimente” durchfĂŒhren kann und bin nach wie vor der Überzeugung, dass dies eine ideale TĂ€tigkeit ist, um das Programmieren zu erlernen. Man braucht nicht viel (ein Browser genĂŒgt) und man kommt auch sehr schnell zu einem visuellen Ergebnis. In meiner TĂ€tigkeit als Ausbilder habe ich bemerkt, dass viele angehende Programmierer Freude daran haben, etwas zu programmieren, was auch visuell ansprechend ist.

Freier Fall

FĂŒr den Anfang gefĂ€llt mir eine Formel besonders gut: der freie Fall.

h=\frac{(g \cdot t^2)}{2}

  • h = die Fallstrecke nach der Zeit t
  • g = Fallbeschleunigung (auf der Erde etwa \frac{9.81 m}{s^2}
  • t = Zeit in Sekunden

Umsetzung

  • Programmieren werde ich das Beispiel auf plnkr.co, das ist sehr einfach zugĂ€nglich und der Funktionsumfang genĂŒgt vollkommen.
  • die graphische Umsetzung werde ich mit SVG programmieren. RaphaĂ«l eignet sich hierzu sehr gut
  • Am unteren Bildrand soll noch der Boden gezeichnet werden, der Boden soll den Fall abrupt stoppen.

Das Ergebnis

…findet sich hier.

Wie weiter

Es ist schon erstaunlich, was man mit dem Browser heute in sehr kurzer Zeit machen kann und irgendwie macht das direkt Laune ein kleines Spiel zu programmieren.

AngularJS allow invalid values to be set on the model

The default behavior of AngularJS when you have a validator on an input field is to set the model to undefined if the validation failed.  This might be convenient for most cases, but sometimes you want to have the invalid value in your model.

It is really easy to tell Angular to allow invalid values on your model by specifying the option allowInvalid on the ng-model-options.

<input type="email" ng-model="model" ng-model-options="{allowInvalid: true}" />

I plunked something that demonstrates both the default behavior and the option enabled:

http://plnkr.co/edit/OlkS5U?p=info

Have fun
Christian