Edit up the 'rps-teams' project (#581)
This commit is contained in:
parent
9630e9dd18
commit
40101e60bd
@ -8,29 +8,28 @@ Massively multi-player rock paper scissors!
|
|||||||
|
|
||||||
https://youtu.be/8ztOmdZi5Pw
|
https://youtu.be/8ztOmdZi5Pw
|
||||||
|
|
||||||
Playing rock paper scissors is usually a two player game... but it works with much more players too!
|
Playing rock paper scissors is usually a two player game... but it works with many more players too!
|
||||||
When playing with more than two players, it becomes a team game: all players shake at the same time,
|
When playing with more than two players, it becomes a team game: all players shake at the same time,
|
||||||
then the number of **rock**, **paper**, **scissors** is tallied between all the players.
|
then the number of **rock**, **paper**, **scissors** is tallied between all the players.
|
||||||
The team with the most players wins the game.
|
The team with the most players wins the game.
|
||||||
|
|
||||||
Starting from the [basic version of the RPS game](/projects/rock-paper-scissors), we are going
|
Starting with the [basic version of the RPS game](/projects/rock-paper-scissors), we are going
|
||||||
to change the code so that the @boardname@ counts and displays the number of players in the same team.
|
to change the code so that the @boardname@ counts and displays the number of players on the same team.
|
||||||
Using the **radio** communication, the @boardname@ will send its status and receive the status of other boards.
|
The @boardname@ will use **radio** communication to send its status and receive the status of the other boards.
|
||||||
|
|
||||||
Let's get started!
|
Let's get started!
|
||||||
|
|
||||||
## Starting blocks
|
## Starting blocks
|
||||||
|
|
||||||
Let's start form a . The basic version picks the weapon in a ``|on shake|``
|
Let's start out with the code from the original game. The basic version picks one of the tools in a ``||input:on shake||`` event and displays an icon accordingly. Take a peek at the code below to refresh your memory.
|
||||||
event and display an icon accordingly. Take a peek at the code below to refresh your memory on that game.
|
|
||||||
|
|
||||||
```blocks
|
```blocks
|
||||||
let weapon = 0
|
let tool = 0
|
||||||
input.onGesture(Gesture.Shake, () => {
|
input.onGesture(Gesture.Shake, () => {
|
||||||
weapon = Math.random(3)
|
tool = Math.random(3)
|
||||||
if (weapon == 0) {
|
if (tool == 0) {
|
||||||
basic.showIcon(IconNames.SmallSquare)
|
basic.showIcon(IconNames.SmallSquare)
|
||||||
} else if (weapon == 1) {
|
} else if (tool == 1) {
|
||||||
basic.showIcon(IconNames.Square)
|
basic.showIcon(IconNames.Square)
|
||||||
} else {
|
} else {
|
||||||
basic.showIcon(IconNames.Scissors)
|
basic.showIcon(IconNames.Scissors)
|
||||||
@ -40,19 +39,18 @@ input.onGesture(Gesture.Shake, () => {
|
|||||||
|
|
||||||
## Step 1: Refactoring the rendering
|
## Step 1: Refactoring the rendering
|
||||||
|
|
||||||
**Refactoring** is a funny word used in coding which pretty much means ``reorganizing``. In this case,
|
**Refactoring** is a funny word used in coding which pretty much means ``reorganizing``. In this case, we are going to move the code that displays the rock/paper/scissor icon into its own ``||basic:forever||`` loop.
|
||||||
we are going to move the code that displays the rock/paper/scissor icon into its own ``|forever|`` loop.
|
|
||||||
|
|
||||||
```blocks
|
```blocks
|
||||||
let weapon = 0
|
let tool = 0
|
||||||
input.onGesture(Gesture.Shake, () => {
|
input.onGesture(Gesture.Shake, () => {
|
||||||
weapon = Math.random(3)
|
tool = Math.random(3)
|
||||||
})
|
})
|
||||||
|
|
||||||
basic.forever(() => {
|
basic.forever(() => {
|
||||||
if (weapon == 0) {
|
if (tool == 0) {
|
||||||
basic.showIcon(IconNames.SmallSquare)
|
basic.showIcon(IconNames.SmallSquare)
|
||||||
} else if (weapon == 1) {
|
} else if (tool == 1) {
|
||||||
basic.showIcon(IconNames.Square)
|
basic.showIcon(IconNames.Square)
|
||||||
} else {
|
} else {
|
||||||
basic.showIcon(IconNames.Scissors)
|
basic.showIcon(IconNames.Scissors)
|
||||||
@ -60,24 +58,23 @@ basic.forever(() => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Step 2: send status via radio
|
## Step 2: Send status via radio
|
||||||
|
|
||||||
We send the value of ``weapon`` via radio to other @boardname@ in the ``|forever|``.
|
We send the value of ``tool`` over the radio to the other @boardname@ in the ``||basic:forever||`` loop. Since a radio packet may or may not arrive, it's a good idea to keep sending them.
|
||||||
Since radio packet may or may not arrive, it's a good idea to keep sending them.
|
|
||||||
|
|
||||||
We also set the radio group and send the device serial number (a number that uniquely identifies a @boardname@) as we will need that later.
|
We also set the radio group and send the device serial number (a number that uniquely identifies a @boardname@) as we will need that later.
|
||||||
|
|
||||||
```blocks
|
```blocks
|
||||||
let weapon = 0
|
let tool = 0
|
||||||
input.onGesture(Gesture.Shake, () => {
|
input.onGesture(Gesture.Shake, () => {
|
||||||
weapon = Math.random(3)
|
tool = Math.random(3)
|
||||||
})
|
})
|
||||||
|
|
||||||
basic.forever(() => {
|
basic.forever(() => {
|
||||||
radio.sendNumber(weapon)
|
radio.sendNumber(tool)
|
||||||
if (weapon == 0) {
|
if (tool == 0) {
|
||||||
basic.showIcon(IconNames.SmallSquare)
|
basic.showIcon(IconNames.SmallSquare)
|
||||||
} else if (weapon == 1) {
|
} else if (tool == 1) {
|
||||||
basic.showIcon(IconNames.Square)
|
basic.showIcon(IconNames.Square)
|
||||||
} else {
|
} else {
|
||||||
basic.showIcon(IconNames.Scissors)
|
basic.showIcon(IconNames.Scissors)
|
||||||
@ -89,12 +86,10 @@ radio.setTransmitSerialNumber(true)
|
|||||||
|
|
||||||
## Step 3: the team roster
|
## Step 3: the team roster
|
||||||
|
|
||||||
So all players are constantly broadcasting which face they picked to other players.
|
All players are constantly broadcasting to the other players which tool they picked.
|
||||||
Let's add the code that receives those status and counts them.
|
Let's add the code that receives this status and counts it.
|
||||||
|
|
||||||
We are going to add an **Array** variable that contains all the players in the same team as the current player.
|
We'll add an **[Array](/types/array)** variable that contains all the players on the same team as the current player. This array, named ``players``, is like your team roster: it contains the list of @boardname@ serial numbers that are using the same tool as you.
|
||||||
That array, named ``players``, is like your team roster: it contains the list of @boardname@ serial numbers
|
|
||||||
that have the same weapon as you.
|
|
||||||
|
|
||||||
```block
|
```block
|
||||||
let players: number[] = [0]
|
let players: number[] = [0]
|
||||||
@ -102,23 +97,22 @@ let players: number[] = [0]
|
|||||||
|
|
||||||
## Step 4: Receiving a message (part 1)
|
## Step 4: Receiving a message (part 1)
|
||||||
|
|
||||||
In an the ``|on radio received|`` event, we receive the status from another @boardname@. Click on the **gearwheel*
|
In an ``||radio:on radio received||`` event, we receive the status from another @boardname@. Click on the **gearwheel** to add the ``serial`` parameter as we will need it to identify who sent that packet.
|
||||||
to add the ``serial`` parameter as we will need it to identify who sent that packet.
|
|
||||||
|
|
||||||
We compute three values from the data received:
|
We compute three values from the data received:
|
||||||
|
|
||||||
* ``match``, a boolean value indicating whether the weapon of the other @boardname@ matches our current weapon
|
* ``match`` - a boolean value indicating whether or not the tool of the other @boardname@ matches our current tool
|
||||||
* ``player_index``, the position in the array of the other board's serial number. It will be -1 if it is not in the array
|
* ``player_index`` - the position in the array of the other board's serial number. It will be `-1` if it is not in the array
|
||||||
* ``found``, a boolean value indicating whether the @boardname@ serial number is part of the ``players`` array
|
* ``found`` - a boolean value indicating whether or not the @boardname@ serial number is part of the ``players`` array
|
||||||
|
|
||||||
```blocks
|
```blocks
|
||||||
let match = false
|
let match = false
|
||||||
let player_index = 0
|
let player_index = 0
|
||||||
let players: number[] = [0]
|
let players: number[] = [0]
|
||||||
let weapon = 0
|
let tool = 0
|
||||||
let found = false
|
let found = false
|
||||||
radio.onDataPacketReceived(({ receivedNumber, serial }) => {
|
radio.onDataPacketReceived(({ receivedNumber, serial }) => {
|
||||||
match = weapon == receivedNumber
|
match = tool == receivedNumber
|
||||||
player_index = players.indexOf(serial)
|
player_index = players.indexOf(serial)
|
||||||
found = player_index >= 0
|
found = player_index >= 0
|
||||||
})
|
})
|
||||||
@ -131,17 +125,17 @@ There are two cases that we need to handle when looking at ``match`` and ``found
|
|||||||
* **if** we have a ``match`` **and** the player is ``not found`` in the list, **then** we **add** it to ``players``
|
* **if** we have a ``match`` **and** the player is ``not found`` in the list, **then** we **add** it to ``players``
|
||||||
* **if** we don't have a ``match`` **and** the player is ``found`` in the list, **then** we **remove** it from ``players``
|
* **if** we don't have a ``match`` **and** the player is ``found`` in the list, **then** we **remove** it from ``players``
|
||||||
|
|
||||||
We turn the two rules above into two ``if`` statement where the serial number is added or removed.
|
We turn the two rules above into two ``||logic:if then||`` statements where the serial number is added or removed.
|
||||||
|
|
||||||
```blocks
|
```blocks
|
||||||
let match = false
|
let match = false
|
||||||
let player_index = 0
|
let player_index = 0
|
||||||
let players: number[] = [0]
|
let players: number[] = [0]
|
||||||
let weapon = 0
|
let tool = 0
|
||||||
let found = false
|
let found = false
|
||||||
let temp = 0
|
let temp = 0
|
||||||
radio.onDataPacketReceived(({ receivedNumber, serial }) => {
|
radio.onDataPacketReceived(({ receivedNumber, serial }) => {
|
||||||
match = weapon == receivedNumber
|
match = tool == receivedNumber
|
||||||
player_index = players.indexOf(serial)
|
player_index = players.indexOf(serial)
|
||||||
found = player_index >= 0
|
found = player_index >= 0
|
||||||
if (match && !(found)) {
|
if (match && !(found)) {
|
||||||
@ -153,26 +147,24 @@ radio.onDataPacketReceived(({ receivedNumber, serial }) => {
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
## Step 6: reseting the team
|
## Step 6: Reseting the team
|
||||||
|
|
||||||
What if another player would leave the game? He would stop broadcasting its status and it would stay in our
|
What if some of the other players leave the game? They would stop broadcasting their status but would still stay in our list of players. To avoid this problem, we reset the ``players`` array each time we shake:
|
||||||
list of players. To avoid this problem, we reset the ``players`` array each time we shake:
|
|
||||||
|
|
||||||
```block
|
```block
|
||||||
input.onGesture(Gesture.Shake, () => {
|
input.onGesture(Gesture.Shake, () => {
|
||||||
let players: number[] = [0]
|
let players: number[] = [0]
|
||||||
let weapon = Math.random(3)
|
let tool = Math.random(3)
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
## Step 7: showing team score
|
## Step 7: Showing team score
|
||||||
|
|
||||||
The team score is the number of players in that team... which boils down to the ``length`` of the ``players``
|
The team score is the number of players in that team... which is really just the ``length`` of the ``players`` array. We add a ``||basic:show number||`` block in the ``||basic:forever||`` loop to display it.
|
||||||
array. We add a ``|show number|`` block in the ``|forever|`` loop to display it.
|
|
||||||
|
|
||||||
```block
|
```block
|
||||||
let players: number[] = [0]
|
let players: number[] = [0]
|
||||||
let weapon = 0
|
let tool = 0
|
||||||
basic.forever(() => {
|
basic.forever(() => {
|
||||||
basic.showNumber(players.length)
|
basic.showNumber(players.length)
|
||||||
})
|
})
|
||||||
@ -180,23 +172,23 @@ basic.forever(() => {
|
|||||||
|
|
||||||
## The final code
|
## The final code
|
||||||
|
|
||||||
Now it's time to glue all together the pieces of our program.
|
Now, it's time to glue together all the pieces of our program.
|
||||||
Go carefully through all the steps and assemble the various features. Eventually, it should look
|
Go carefully through all the steps and assemble the various features. Eventually, it should look
|
||||||
like the following program. Download it and plays with your friend**ssss**!
|
like the following program here. Download and play it with your friend**ssss**!
|
||||||
|
|
||||||
```blocks
|
```blocks
|
||||||
let temp = 0
|
let temp = 0
|
||||||
let found = false
|
let found = false
|
||||||
let player_index = 0
|
let player_index = 0
|
||||||
let weapon = 0
|
let tool = 0
|
||||||
let match = false
|
let match = false
|
||||||
let players: number[] = []
|
let players: number[] = []
|
||||||
input.onGesture(Gesture.Shake, () => {
|
input.onGesture(Gesture.Shake, () => {
|
||||||
players = [0]
|
players = [0]
|
||||||
weapon = Math.random(3)
|
tool = Math.random(3)
|
||||||
})
|
})
|
||||||
radio.onDataPacketReceived( ({ receivedNumber, serial }) => {
|
radio.onDataPacketReceived( ({ receivedNumber, serial }) => {
|
||||||
match = weapon == receivedNumber
|
match = tool == receivedNumber
|
||||||
player_index = players.indexOf(serial)
|
player_index = players.indexOf(serial)
|
||||||
found = player_index >= 0
|
found = player_index >= 0
|
||||||
if (match && !(found)) {
|
if (match && !(found)) {
|
||||||
@ -207,10 +199,10 @@ radio.onDataPacketReceived( ({ receivedNumber, serial }) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
basic.forever(() => {
|
basic.forever(() => {
|
||||||
radio.sendNumber(weapon)
|
radio.sendNumber(tool)
|
||||||
if (weapon == 0) {
|
if (tool == 0) {
|
||||||
basic.showIcon(IconNames.SmallSquare)
|
basic.showIcon(IconNames.SmallSquare)
|
||||||
} else if (weapon == 1) {
|
} else if (tool == 1) {
|
||||||
basic.showIcon(IconNames.Square)
|
basic.showIcon(IconNames.Square)
|
||||||
} else {
|
} else {
|
||||||
basic.showIcon(IconNames.Scissors)
|
basic.showIcon(IconNames.Scissors)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user