Acknowledged. This will be fixed soon. Thanks
Best posts made by info-creaticode
-
RE: Some avatars aren't shown to select until searched for
-
Wishlist for New Models
If you are looking for a particular 3D model that is not in our library, please reply to this topic. If you can include an example picture of it, it would be more clear what you are looking for. We will try to fulfill these requests as best as we can. Please make sure you do not submit duplicate requests by searching for it first.
Thanks
CreatiCode Support -
RE: Raycasting.
Basically it is drawing some arrows from the object to all directions, and when the arrow touches some other object, it triggers some actions.
More info here:
https://www.forum.creaticode.com/topic/41/checking-for-object-collisions-with-ray-cast
-
Number of Seconds since 2000
Introduction
In MIT Scratch, you can already manage dates using the “days since 2000” block. However, if you need a more granular control of date and time, you can use this new block:
This block will return the number of seconds that have passed between the given timestamp and the beginning of 2000.01.01.
Input Format
The input is a timestamp, which contains the date, a “T”, and then the time. The date is represented as year:month:day. The time is represented as hour:minute:second. Each field has to be 2 digits, except that the year has to be 4 digits.
The timestamp is assumed to be the local time of the computer that’s running this program. If you want to use the UTC time, which is the same across the world, then append a “Z” at the end of the timestamp, such as “2024.01.01T10:00:00Z”.
If the input is left empty, then the current time is used:
Calculating Time Difference
With this new block, you can easily calculate how many seconds are between 2 timestamps. You just need to run this new block for both timestamps, then calculate the difference between them:
Converting to Date
You can also convert the number of seconds back to a Date object. For example, the program below first gets the number of seconds for a specific timestamp, then create a date object using that result, and we get the same timestamp as our input:
-
3D - A Spinning Earth (Difficulty: 1)
Key Topics Covered
Introduction
In this tutorial, you will learn to create a spinning Earth:
Step 1 - Initialize An Empty Scene
First, create a new project, and load an empty scene using the “initialize 3D scene” block.
By default, it will create an empty scene with nothing but a blue background:
Step 2 - Set the Background Starfield
Next, use the “set sky” block to create a better-looking backdrop:
You should get a starfield with the Sun on the right.
Step 3 - Add a Big Sphere
Next, add a sphere with a large diameter of 10000 to the scene. Don’t worry about its color yet.
The sphere would look brighter on the side that faces the Sun.
Step 4 - Add Earth Texture
Now we need to update the sphere’s texture with the Earth. Add the “update texture” block, click the “Please select” input box, then search for “Earth” in the library window.
Step 5 - Flip the Earth Texture
You might have noticed an issue with the texture: the continents are upside-down. We need to flip the texture vertically to correct this issue. This can be done by changing the vertical repeat count from 1 to -1.
Step 6 - Make the Earth Spin
To make the Earth object spin, we can use the “set speed” block. Note that the Earth needs to be spinning from “left” to "right, so the “Z-rotation” speed needs to be negative.
Now your Earth object should be spinning slowly.
Step 7 - Highlight Around the Earth
Lastly, to make the Earth object glow in blue lights, we can create a new highlight layer, then add the sphere to that layer.
Now your Earth object should carry a blue light around it.
Next Steps
You can try to use a similar method to build other projects. Here are some example ideas:
- A Different Planet: You can change Earth to other planets like Mars;
- A Spinning Trophy: You can try to make a trophy object spin and shine.
-
RE: "Important Forum Announcement" - Question
@011830-0a42ef84 said in "Important Forum Announcement" - Question:
@info-creaticode am I able to be a moderator/mod helper?
Currently 2 helpers are good enough. If they are overwhelmed we might need to add more. Thanks for the offer.
-
How to record and share screen recordings as gifs
Introduction
When you need to explain how a project should work, the best way is to make a screen recording of the stage. This short article will explain which tools you can use to record the screen, and also how to share the gif file to get a URL for it.
Screen Recording on Windows
If you are using a Windows computer, we recommend a free tool named “ScreenToGif”, which you can download here: https://www.screentogif.com/
Here is a short video explaining how to use it: https://www.yo utube.com/watch?v=ELfCBzN1Mtc
Screen Recording on Macbook
If you are using a Macbook, you can use a free tool called “Giphy Capture”: https://giphy.com/apps/giphycapture
Here is a short video showing how to use it: https://www.yo utube.com/watch?v=m-4cJMBGfS4
Share your gif file
Once your gif file is ready, you can share it this way:
-
Go to the “My Stuff” page at https://play.creaticode.com/mystuff, and make sure you are logged in.
-
Select “My Files” tab on the bottom left
-
Click the “+Share a New File” button on the top right
-
In the pop up window, click “Click to upload file”, and then select the gif file from your computer.
-
Click the green button that says “upload and share with the CC Attribution license” at the bottom.
After that, you will see the new file in the list of files, and then you can click “Copy file URL” button for that file, which will copy the URL to the clipboard, which would look like this: https://ccdn.creaticode.com/user-files/BfemEPCxatY6MMAPs/castfireball.gif
-
-
RE: Multiplayer 3D games
We are working on fixing the cloud blocks. Should be within next few days. Sorry about that.
-
Shape-Based Particle Emitters
Introduction
You learned about Single-Point Particle Emitter, which generates particles from a single point in the 3D space.
In this article, we will discuss “shape-based” emitters, which generate particles from within a 3D shape like a box. They allow us to produce very different visual effects.
Box Emitters
The box emitter is simply a transparent 3D box, and it can generate new particles from any random point inside this box. We can not see this box since it is transparent, but we can indirectly see its shape by where the particles are generated.
To use the box emitter, we need 2 steps:
- Select the “Box” shape when creating the emitter
- Configure the size of the box by its minimum and maximum X/Y/Z positions
Here is a simple example:
This program creates a box emitter that is 400 units in each dimension. For example, in the X dimension, the minimum is -200 and the maximum is 200, so the x position of new particles can be any random value between -200 and 200. When you run this program, you can see the particles are all confined within this box-shaped region:
Sphere Emitters
The shape of the emitter can also be a sphere. When we configure the sphere shape, we can set its size using the “radius” parameter.
There is also a “range” parameter (between 0 and 1), which controls the range of possible values along the radius. You can think of “range” as “thickness”:
- When “range” is 0, the particles will only be generated on the surface of the sphere, and not inside it.
- When “range” is 1, the particles can be generated at any random point on the surface or inside the sphere.
- When “range” is between 0 and 1, the particles will not be generated near the center of the sphere, but can be generated on the surface or near the surface.
Here is an example program with a range of 0:
As shown, particles are only appearing on the surface of the sphere:
Hemisphere Emitters
Hemisphere emitters generate particles from a half-sphere shape. You can specify its radius and range the same way as the sphere emitters.
One thing special about hemisphere emitters is that we can rotate the half sphere to different directions. As shown below, when we rotate it around X-axis for 90 degrees, the new particles are all generated at the bottom half of the sphere:
Cylinder Emitters
The emitter can also take a cylinder shape. We can control the radius of the circle, and also the height of the cylinder.
The “range” parameter also works for cylinders. You can think of it as controling the “thickness” of the cylinder’s skin. For example, when radius 0.5, the thickness of the cylinder skin is half of the radius:
The cylinder shape also supports an additional parameter of “direction randomness”. This only matters when we set the particles to not face the camera all the time, and we will see the particles facing different random directions when we set “direction randomness” to 100:
Lastly, we can rotate the cylinder emitter as well. For example, we can make it “lie down”:
Cone Emitters
For the cone-shaped emitter, we can console these parameters:
- Radius: The radius of the bottom circle of the cone
- Angle: The opening angle of the cone. Note that the angle and the radius would imply the height of the cone, so we won’t need another “height” parameter.
- Radius Range: This range value applies along the radius direction. When it is 0, the particles will only be generated on the surface of the cone. When it is 1, the particles may come out from anywhere inside the cone or on its surface.
- Height Range: This range value applies along the height of the cone. When it is 0, the particles will only emerge from the bottom of the cone, and when it is 1, the entire height can generate particles.
We can rotate cone emitters as well.
-
RE: Suggestions for both the forums and CreatiCode!
@mathew139616-10db496a
Thanks for the suggestions.
For unpublished projects, the authors do not want it to be seen, so we can not let anyone see it, even the original author.
We can look into adding the notifications.
For forum, most of the questions are fairly specific to CreatiCode so ChatGPT can’t answer them well. Don’t worry, we have enough staff to answer questions, and there are also a few active users who often help out.
-
RE: Does saving private data act as like a "secret" or "environment variable"?
It should not be used to store real secrets like passwords. The reason is that this block runs on the “client” side (the user’s browser), so when the data is sent over the Internet to the webserver, it is exposed in the network package.
However, for most games/projects you build for learning, it should be good enough.
The “private” mode is meant to store data specific for one user. Say 100 users are running your shared game. Suppose each of them can specify a secret passcode that can be used to save or load game progress. You can use this block and use the “private” mode, so the data is separated by user ID, and 2 users can’t see each other’s data.
-
RE: Wishlist for New Models
Please check out this new avatar:
Its source is at https://sketchfab.com/3d-models/jotaro-kujo-idle-unity-03309a5dd9bc413fa0105597a7755ae9
The original author is https://sketchfab.com/Maxime66410
-
RE: Hitboxes
That’s also a good option, if the hit box must have an empty square hole inside it.
Here is an example of how to do it using “compound shape”. You just need to draw the costume using 4 boxes:
https://play.creaticode.com/projects/670083d55689190abfe5461f
-
RE: Customizable blocks.
@106809nes
It would be interesting. We can certainly add this feature, but frankly it will be fairly low priority at this point, compared to other features on our list.
-
RE: What is the email that CreatiCode uses for Google Sheets?
Great question. The email we use is “user-606@creaticode.iam.gserviceaccount.com”
-
RE: Some avatars aren't shown to select until searched for
FYI this issue is fixed now.
-
RE: Broken append block
We can see the issue. Will post a fix soon. Thanks for the feedback.
-
RE: new block ideas
Thanks for the kind offer. It is not easy to open up our code base for external contribution at this point. If you are looking for something challenging to do, it would be very helpful to us and to our user community if you can create more interesting projects that demonstrate the potential of our rich set of blocks, especially the AI, 3D, widgets, 2D physics engine and cloud blocks.
-
RE: Using an AI other than CreatiCode if you can't find what you are looking for
Hi everyone, this is an engaging topic, and it’s great to see a thoughtful and respectful debate from both sides.
From CreatiCode’s perspective, our main goal is to help K-12 students cultivate creativity and logical thinking through coding activities. One common challenge they face is finding or creating quality images that fit the story or game they’re building. Many students struggle with drawing, especially digitally, and often can’t afford professional images online. To address this, we provide AI image tools that allow them to generate or find high-quality backdrops and sprites for their projects.
Additionally, using these tools offers another key benefit: students can hone their AI prompting skills. Generating the perfect image for a project requires giving clear, detailed descriptions and refining prompts based on the results. These skills will be increasingly valuable in a future shaped by AI technology.
There are ongoing philosophical debates about whether AI-generated images infringe on artists’ copyrights or stifle creativity. While we don’t take a definitive stance on this matter, we ensure that all images produced with CreatiCode’s AI tools are fully licensed. Users retain complete copyright over these images, allowing them to use them in their CreatiCode projects without concern.
-
RE: new block ideas
@luna
The widget blocks work in both 2D and 3D projects. There are good and bad videos on Youtube. If anyone uses bad content from Youtube, we will delete the project and ban the author.
-
RE: new block ideas
With regard to the “play sound from URL” block, you can actually use the youtube block instead. You just need to set its width and height to 0.
You can find almost every possible sound or background music you want on Youtube. For example, there are at least 50 videos for horse noise.
-
RE: even when logged in, front page says login
Regarding your feedback below:
The forum and website feel a bit seperate, and the forum has features the site doesn’t, like dark mode themes.
At the top of the navigation bar in the forums, maybe there could also be a link to go back to CreatiCode instead of having to press back in my browser button a million times to get back to CreatiCode.com.
I also think the whole thing where you have to make a forum account using a CC account and all is a bit confusing and unnecessarily complicated. Like you have two different usernames (possibly) and profiles and bios, even though it’s the same site but different subdomain (forum.).
If you’re logged in on CreatiCode, then why can’t that same login session/token/whatever just apply to the forum? I get that the subdomain thing might be an issue but if so then the forums could just be moved to https://app.creaticode.com/forums or wherever within the main domain right?We are aware of this disconnection. It’s mostly because the forum is a third party project that we do not have time to make too much changes yet. We will optimize it over time.
-
RE: 3d avatar style I like
That’s called the “Chibi” style. We will sure add more such avatars when I can source them with proper license.
-
RE: Feature request: a block to make a string backwards and other text stuff
Thanks for the proposals. We can definitely add these blocks, but we would like to see more upvotes before committing to them.
-
RE: Feature request: a block to make a string backwards and other text stuff
Can you explain what kind of project would make use of the “cowsay” block?
-
RE: Feature request: a block to make a string backwards and other text stuff
You know, we should only add blocks that’ll be widely used in many projects, so it doesn’t seem cowsay is a good candidate for that?
-
RE: Feature request: a block to make a string backwards and other text stuff
Agreed. We can put that on our list.
-
Nested Loops
Prerequisite
What are Loops?
A “loop” is a block for playing other blocks repeatedly. Below are some loop blocks you can use on the CreatiCode playground;
What are Nested Loops?
When you put one loop inside another loop, it becomes a “nested loop”. You can even have a third loop inside the inner loop.
How Nested Loops Work?
When you run a program with a nested loop, the inner (child) loop will work like a normal loop. However, because of the outer (parent) loop, the inner loop itself will be repeated.
Here is a step-by-step example:
Step 1: The main loop is played.
Step 2: The Nested loop is started.
Step 3: The blocks inside the nested loop are played until the condition of the nested loop is completed.
Step 4: The blocks after the nested loop are played (if there are any).
Step 5: The main loop is restarted.
Note: All of the above 5 steps keep repeating until the condition of the main loop is completed.
For example, as shown below, “repeat until ” is the nested loop, which keeps the monkey moving until it touches the edge of the stage. And “repeat (5)” is the main loop which repeats the nested loop 5 times.
Use of Nested Loops
We use Nested loops when we want to repeat multiple blocks at the same time, until multiple conditions are completed.
For example, as shown below, nested loops are used to make the monkey move and eat bananas at the same time.
-
AI - Recognize 0's and 1's (Difficulty: 4)
Key Topics Covered
Introduction
There are many AI applications that can recognize numbers automatically. For example, when we deposit a check, we can take a picture of it on the phone, and the app will recognize the account numbers and the deposit amount written on the check.
In this tutorial, you will build a smart program that can recognize whether a hand-written number is 0 or 1:
Step 1 - Create a New Project
First, please create a new project, remove Sprite1 with Cody, and rename the “Empty1” sprite to “AI”. Please also add an empty sprite named “Pen”.
The "Pen’ sprite will allow the user to draw a number on the stage, and the “AI” sprite will contain code to guess whether this number is 0 or 1.
Step 2 - The Drawing Area
We’ll start with the “Pen” sprite. First, when the program starts, let’s draw a square area to indicate where the user can draw the number. This can be done using the “draw rectangle” block in the “Looks” category. Note that this square will be located at the center, with both width and height of 200. Please set its “fill” color to 100% transparent, and pick any border color you like.
Here is what the square looks like:
Step 3 - Initialize the “Pen” Extension
Next, please add the “Pen” extension, and set the pen’s color to black, size to 10. We will also erase all drawings from the pen.
Step 4 - A Forever Loop To Move the Pen Sprite
We will allow the user to use the mouse pointer to draw. To do that, we need to make the Pen sprite follow the pointer. You can use a forever loop to make the Pen sprite keep going to the position of the mouse pointer.
Now if you move the mouse, you will see the position of the “Pen” sprite changes with it:
Step 5 - Mouse Down to Draw
To use the mouse pointer as the pen, we can check if the mouse is pressed down. Whenever it is, we will put the pen down as well; whenever the mouse is not pressed down, we will lift the pen up.
Now our drawing area is ready for drawing:
Step 6 - The “Clear” Button
To allow the user to clear the drawing and restart, let’s add a “clear” button. Please load the “widget” extension, then find the “add button” block.
Run the program again, and you will see the button at the bottom:
When the button is clicked, we need to erase all the drawings:
Step 7 - The “Guess” Button
Please add another button “Guess” at the bottom right. When it is clicked, we’ll send a message to the “AI” sprite to take a guess of the number.
Step 8 - Prepare the AI Sprite
Now we are ready to work on the AI sprite. First, please draw a small square in the “AI” sprite’s costume, so we can see where it is:
Step 9 - Scan the Middle Row
When the “AI” sprite receives the “guess” message, it should scan the middle row from left to right. We can create a new variable “x”, and use a for-loop to set x to go from -100 to 100 at a step size of 5.
Click the “Guess” button to test it:
Step 10 - Touching Black Before and After Each Move
Now we are going to check whether our AI sprite is touching the black color of the drawing at each step. We will use 2 new variables to keep track: “touching before move” and “touching after move”. They will be set to the value of “touching black color” before and after the “go to” block. To view the values in slow motion, we will add a 1-second wait after each move:
Now let’s test it. When our AI sprite touches the black color for the first time, “touching before move” will still be false, but “touching after move” will become “true”.
Step 11 - Stamping the Strokes
Now we can detect a black stroke using the 2 variables we have created. We will make a stamp whenever the AI sprite finds that it is touching the black color after the move, but not touching it before the move.
Now let’s test it. No matter how many strokes we draw, the AI sprite will make a stamp the first time it touches each stroke:
Step 12 - Counting the Strokes
Now we can count how many strokes our AI sprite is detecting. We will use a new variable named “counter”, and instead of making a stamp, we also increase the counter by 1.
Run the project, and you will find that the counter will tell us how many vertical strokes are there. More specifically, it is telling how many “edges” are there, with each edge defined by going from white to black color.
Step 13 - 0 or 1?
Finally, we are ready to answer the question: whether the user has drawn a 0 or 1?
The insight is that when the user draws a 1, there is only one edge; but if the user draws a 0, there are 2 edges.
Therefore, we can take a guess based on the value of “counter”. If it is 1, then the user has drawn a “1”. If it is 2, then the user has drawn a “0”. Of course, to keep it simple, we are assuming the user can only draw a 0 or 1.
Please test it a few times:
Step 14 - Handling Smaller 0’s
When the user draws a very small or very thin “0”, we can only detect one edge, so we will guess incorrectly.
That is because our AI sprite box is touching both strokes at the same time. So to fix it, we simply need to make our AI sprite much smaller, such as a size of 5:
Step 15 - Speed Up
Lastly, to speed up our AI detector, we can make a new block named “guess”, and run it without screen refresh:
Then we move all the blocks into that block’s definition stack:
Now our program runs much faster:
Challenges
This tutorial shows a very common technique that analyzes an image using edge detection. As a challenge, please try to extend this program to recognize some other numbers. You need some smart ideas to handle them in a robust way.
For example, if you are trying to recognize the number “6”, you will need to scan all rows, not just the middle row. Then you can check if the number of edges is 1 at the top, becomes 2 towards the bottom, and then reverts to 1 at last.
Similarly, if you are trying to recognize the number “8”, you can check if the number of edges is 2 at the top and bottom, but 1 in the middle.
Here is a demo of an enhanced version of the project:
-
RE: Feature request: a block to alphabetize lists and tables
No problem. All letters are represented by numbers (all things are numbers in computers), so you can compare letters just the same way as letters.
-
Video Planes for Showing a Video Clip
Introduction
You can add a plane in the 3D world that can automatically play a video clip with this block:
Parameters:-
URL of a video file in mp4 format. Note that YouTube video links do not work.
-
width and height of this plane
-
an optional name for this plane
Example
You can follow these steps to add the video plane:-
Find or create a mp4 video file (make sure it’s appropriate).
-
Share the file online. One easy way is to use the “My Files” tab in the “My Stuff” page: https://play.creaticode.com/mystuff/files
That page allows you to upload a file and copy its public URL.
- Use the video’s public URL in the video plane block. Note that you can move or rotate this plane the same way as any other 3D object.
It will look like this:
-
-
2-Player Online 3D Doom (Difficulty: 6)
Overview Podcast
Here is an interesting podcast of 2 AI hosts discussing this tutorial to unpack some of the most challenging concepts:
Introduction
In this tutorial, you will learn how to build a multiplayer shooter game in 3D similar to the classic game “Doom”. Two players (on two separate computers) can play this game against each other.
Since this project is fairly complicated, the completed project is shared below:play.creaticode.com/projects/66e823b5a634f8ee7d92cc88
This tutorial will go through all the key components of this project step by step so that you can understand it thoroughly.
Note that our multiplayer game server only knows about 2D game worlds, but we can use it to support our 3D game, so long as all the objects are on the same ground level. A simple way to think about it is this: if we look down from above the 3D world, then the game world looks like 2D, and a 3D box in the 3D world will look like a 2D square when we look at it from above.
1 - Overview of Sprites
This project contains six sprites:
- Start: This sprite contains code to display the game’s starting screen so the host player can create new games for the guest player to join. It also initializes the 3D world.
- Player: This sprite allows the players (users) to control the two avatars in the 3D world, including handling key events and managing the health/firepower of the players. This is the most complex sprite in this project.
- Bullet: This sprite represents the bullets fired by the players.
- Wall: This sprite is used to create the walls in the 3D world. Players or bullets can not pass through these walls.
- Powerup: This sprite is used to generate new powerup items for “health” or “firepower”. They will appear randomly in the game world periodically, and they will disappear after a while if not collected by any player.
- Winner: This sprite displays the ending screen of the game when either player wins.
2 - “Start” Sprite: Initial Screen
When the user clicks the green flag, we will show an initial screen, which contains a label, an input textbox, and two buttons:
Here is the code for creating this screen in the “Start” sprite:
Note that each game can only be played between 2 users (host and guest), and it is uniquely identified by its name. The default name is “3D Shooter”. If a name is taken, then the host needs to pick a different game name when they create the game, and the guest needs to use the same name to join that game.
3 - “Start” Sprite: Create New Game
After the host user specifies the game name, he/she will click the “Create New Game” button. We will read the game name, and set the ID of this user to “A”, which represents the host player. We will show an error message if the game name is empty, otherwise we will try to create the game.
4 - “Start” Sprite: Create Game
To create a game, we do the following:
- Initialize the 3D scene on this computer;
- Ask the game server to create a new game with the given game name.
- To keep it simple, we will use the default password of “123” and assume the host user is “Player A”.
- The game capacity is 2, which means it will not accept any join request after one host and one guest are in it.
- The game world is set to be 2000 by 2000. Note that this is a 2D game world, so it only has width and height. We assume every object is at the ground level, so we don’t need to specify the world size in the Z dimension.
- If the game world is created successfully, this computer will be connected to the game. Then we can add the host player to the game (will be discussed later), and then wait for the other player (the guest) to join.
- If we are not connected to the game after a short wait, it means we have failed, and the most likely reason is the game name is already taken, or the game server is too busy. Either way, we can ask the user to change the game name and try again.
5 - “Start” Sprite: Initialize 3D Scene
To set up the 3D world, we create a simple “Grass Land” scene, then add a “rectangle cube” with no cap on top, so it becomes the walls on the 4 borders of the world. The size of the world is 2000 by 2000. We set the height of the border wall to 100, so that half of that (50) is above the ground. The avatars will be 100 tall, so the wall will not block our camera that follows the avatar. After the world is created, we also add the health bar and firepower bar on top using the “add bars” block.
6 - “Start” Sprite: Add Health and Firepower Bars
Each player starts with 3 lives, so he/she will lose when hit by bullets 3 times, but can gain lives by collecting health rewards. Each player starts with firepower of 1, and can increase it up to 5 by collecting firepower rewards. The firepower controls the minimum interval between every 2 bullets fired: interval = 2 seconds / firepower. So when firepower is 1, the player can fire every 2 seconds and no sonner; but when firepower is 5, the player can fire every 0.4 seconds.
The current health and firepower values for both players are displayed on top of the stage like this:
The code to add the player name and the health bars is the following. The health bar is represented by 3 square labels in green, and their names start with “health”, then followed by the player’s ID “A” or “B”, and lastly end with a sequence number of 1/2/3.
The code to add the firepower labels is very similar:
7 - “Start” Sprite: Wait for the guest player to join
After the host player creates the game, he/she needs to wait until the guest player has successfully joined the game. We can repeatedly fetch the player information into a table, then check if the number of players is 2. If that’s true, then we show a “Start Game” button, which allows the host player to start the game.
8 - “Start” Sprite: Join Existing Game
Now, let’s look at the guest player side. The guest player needs to input the same game name as the host player, then click the “Join Existing Game” button.
When that button is clicked, we do the following:
- Save the local player to be “Player B”, which represents the guest player.
- Make sure the game name specified by user is not empty
- Join the game
9 - “Start” Sprite: Join the game
To join the game, we will first create the 3D scene at the guest player’s computer, then send a request to the game server to join the game with the given name. This player will be the “Player B”, which represents the guest player.
After waiting some time, we check if we are connected to the game. If so, we create the gust player (to be discussed later); otherwise, we show an error message.
10 - “Start” Sprite: Start the Game
After the guest player joins the game, the “Start Game” button will appear on the host computer. When the host user clicks it, we will send a new message “start game”:
Note that this message is sent to both computers, but only “Original” sprites can receive it. For example, the Player A sprite on the host computer will receive it, but the clone of it on the guest computer will not. This way, the “start game” message is only received and handled for one time on each computer.
11 - “Player” Sprite: Add Players
Now, let’s switch to the “Player” sprite. This sprite represents the player’s avatar in the game world.
To add the host or guest player, we use simply create a clone of the “Player” sprite with different clone IDs: “A” for the host and “B” for the guest. This way, we reuse most of the code to add a player.
When the clone is created, we do the following:
- We initiate a variable “last fire time” to keep track of the last time a fire is shot, which helps us determine when the player can take another shot
- We use two variables, “health” and “firepower”, to keep track of the number of lives and firepower level of each player, which start at 3 and 1. Note that these variables are “private” to each clone of the Player sprite, so the two players can have their own “health” and “firepower” values.
- We will place the two players at two opposite sides of the game world: x of 0, and y of 800 or -800. Note that we use their clone ID to tell whether this is the host or the guest player.
- We add the player to the game, which means we register this player at the game server. The player is “Dynamic”, which means its movement will be tracked and replicated across the two computers.
- We use a “Circle” shape to represent each player. Although each player is a 3D avatar in the 3D world, in the eyes of our game server, they are both represented by a 2D circle with a diameter of 30.
- We will stop the player avatar from going through the Wall objects
- We will allow the player to collect powerup items, which will trigger a message “collect powerup”.
Behind the Scenes
When we register a player to the game server, what happens behind the scenes? The game server simulates what happens in the game world as we play it. At the beginning of the game, when we register a new player, the game server adds a new circle shape to its simulated game world.
In addition, a copy of that player is created on the other user’s computer. For example, when the host user creates a game, his/her code will create the host player “A”, then a clone of player “A” will be created in the guest user’s computer. Similarly, when the guest user joins the game and creates player “B”, it will be replicated in host user’s computer. As a result, on each computer, there are two clones of the “Player” sprite running.
12 - “Player” Sprite: When a player is added to the game
After we run the “add this sprite to game” block, if it is successful, another block will be triggered: “when added to game”. This is an important “hidden” event, because it gives us a chance to fully initialize the player.
This block is called two times on each computer. On the host user’s computer, after the host player is created, this block is triggered for this player (Player A). Later, when the guest user joins the game, a clone of player B is created on the host user’s computer, and this block is triggered again.
When this block is triggered, we do the following:
- Create a 3D avatar to represent this player. Currently it is Superman for the host and Batman for the guest. The avatars will be moved to the initial positions we have specified earlier: x of 0, and y of 800 or -800.
- Although this block is triggered two times on each computer, we will only add a “follow camera” once, only for the avatar that represents the local player. For example, for the host user, his player ID is “A”, so we will only add the follow camera if the clone ID is also “A”. Note that the follow camera’s direction lock is “Free”, which means the user can turn the camera to point at any direction using the mouse. If you are debugging the game, you can skipping adding the follow camera, so you can use the default camera to look at the entire game world easily.
- Lastly, we will add the “Run” animation to the 3D avatar so it knows how to play that animation later.
13 - “Player” Sprite: Handle Game Start
As discussed above, the “original” player sprite on each computer will receive the “start game” message. Here is what we do when we receive that message:
- Remove the “Start Game” button
- If this is the host player (player “A”), then we also need to trigger 2 events: add wall and add powerup. The wall and powerup objects will be replicated on the guest computer, so we don’t need to create them separately on the guest computer. Also, the “add powerup” message is handled by a forever loop that adds a new powerup periodically, so we are not using “broadcast and wait” for that message.
- We set the current animation of the avatar to “Idle”, so when it changes later, we need to tell the other computer.
- Lastly, we start the “handle keys” block, which is a forever loop that handles key inputs. Note that only at this step can the user start to play the game with the keyboard.
14 - “Player” Sprite: Handle Keys
This is the main loop of the game logic, where we continuously check the keys the user is pressing, and update the player avatars accordingly. Specifically, we do the following inside a forever loop:
- Check if we have disconnected from the game server, and show an error message if so. The player gets automatically disconnected from the server if no updates are received from any player in the last 5 minutes. This will help the game server reclaim the resources allocated to a game in case the players have left the game.
- If we are still in the game, we check the SPACE key and fire a shot if enough time has passed.
- We also check the movement keys to determine the moving speed, direction and animation.
- Lastly, we wait a very short time before entering the loop again. This helps reduce the number of messages we send out on the network and avoid too much “network traffic” that will slow down the game server.
15 - “Player” Sprite: Handle Firing Shot
When we detect the SPACE key is pressed down, we check if the current time is more than the last time we fired a shot plus a waiting period. This waiting period is calculated as (2 / firepower). For example, if firepower is 2, then the minimum wait time is 2/2 = 1 seconds.
If we are allowed to fire a shot, we send the “fire” message, which will be handled by the “Bullet” sprite (discussed later). In this message, we need to specify the clone ID of this sprite (“A” or “B”), the x/y positions and the facing direction of this player, so that the Bullet sprite can create a bullet at the same position and direction.
16 - “Player” Sprite: Get Intended Speed and Animation
To create a fun experience that gives the users full control of the avatar’s movement, we will allow the user to use both the mouse and the keyboard at the same time. The mouse will be used to control the camera, and all movements will be relative to the direction of the camera. For example, if we drag the camera to look to the right, the avatar will immediately turn to face the same direction. So when we press “W” to move forward, the avatar will move in the same direction as the camera:
To achieve this effect and keep our code short and clean, we will divide it into 3 cases:
- When the “a” key is pressed, it means the user wants to move left.
- When the “d” key is pressed, it means the user wants to move right
- When neither the “a” or “d” key is pressed, the user wants to move forward/backward or stay still.
The default assumption is that the intended speed is 300 and the intended animation is “Run”, and we can change them as we check the keys.
17 - “Player” Sprite: Handle Move Left or Right
When only the “a” key is pressed, the user wants to move left horizontally. If the “w” or “s” key is pressed at the same time, then the user intends to move diagonally to the left front or left back. Note that we are just setting the “intended dir” and “intended speed” for now, then we will use them to update the avatar later.
Also, all directions are relative to the camera’s “H-Angle”, which is the direction the follow camera is facing. In addition, when the user presses “a” and “s” at the same time, we set the direction to be forward right, and set the speed to negative.
For the “d” key, the logic is exactly the same, though the angles are reversed:
18 - “Player” Sprite: Handle Move Forward or Backward
If neither the “a” or “d” key is pressed, the avatar will run forward under the “w” key, run backward under the “s” key, and stay still when neither key is pressed.
19 - “Player” Sprite: Update player speed/animation/direction
By this point, we have calculated the intended moving speed, moving direction and animation, we need to update it for 3 entities: the player’s avatar on his/her own computer, its 2D representation at the game server, and its copy on the other user’s computer.
This is done in 3 steps:
-
We first compare the local camera’s facing direction and the avatar’s facing direction. If they are not enough (at least different by 0.1 degrees), then we need to update the avatar’s facing direction. For example, this might happen when the user rotate the camera to a different direction. We are using the “synchronously set direction” block, which not only update the direction of this player’s avatar on his/her own computer, but also update the direction on the game server and the other user’s computer.
-
If the intended moving speed or direction has changed, we will use the “synchronously set speed and direction” block to update these values for all 3 representations as well. Note that the “intended dir” is where the avatar is moving, and it may be different from the camera’s direction. For example, when the user presses “a”, the camera may still facing forward, but the intended moving direction is to the left.
-
Lastly, if the intended animation has changed, we need to update the animation for this player’s avatar on this computer and on the other user’s computer. This can be done by broadcasting a message “update animation” to all sprites, and attaching the clone ID and intended animation with that message. We will discuss how that message is handled next.
20 - “Player” Sprite: Handle the “update animation” message
When any sprite receives this message, we will split the attached information and extract the clone ID. If that ID matches the ID of this clone, then we update this sprite’s animation. Recall from #19 that the “animation_info” attached to the message has two parts joined by “_”: “clone ID” and “intended animation”, such as “A_Run”.
21 - “Wall” Sprite: Add 4 Clones
The “Wall” sprite is fairly simple. You can modify it to design any map inside the borders. As an example, we can have four walls on the four sides of the world like this:
To keep the code simple, all the wall objects are the same shape, except that two of them are rotated 90 degrees. They are all clones of the “Wall” sprite with clone IDs of 1, 2, 3 and 4:
When each clone is created, we need to place it at the desired position and direction based on its clone ID. Then, we need to add it to the game so that the game server can create a rectangle of 400 by 50 to represent it in the 2D simulated world at the server. The same clone will also be created on the guest user’s computer.
22 - “Wall” Sprite: Create the 3D Wall Object
When we add the Wall sprite to the game, it has not yet been added to the 3D scene. As discussed earlier, after a sprite is added, the game server will trigger a new event “when added to game”, and this is where we should add the 3D box that represents the wall in the 3D scene. The reason for this is that this event is triggered on both the host computer and the guest computer, which ensures both players can see the walls in their 3D scenes.
The x and y sizes of the 3D box should match the rectangle shape we specified earlier: 400 by 50. The height of the wall does not matter, since the game server only thinks of the wall as a 2D rectangle. However, to make sure the player can not see above the wall, we should make the wall taller than the player’s height of 100. Therefore, we can set z size to 300, so the top half is 150. Depending on the clone ID, we place each box at the desired position and direction.
That is all that we need to do for the walls. We already specified that when a Player touches any Wall sprite, it will be stopped.You can also add 3D cylinders as walls, and you just need to make sure they are added as circle shapes like this:
23 - “Bullet” Sprite: Handle the “fire” message
Next, let’s look at the Bullet sprite. It is slightly more complicated than the Wall sprite. A bullet is created when the “fire” message is received. Note that the Wall is only added at the host computer, but the Bullet can be fired at both computers.
When the “fire” message is received, we first need to make sure only the original Bullet sprite handles it. We check the clone ID to make sure it is “originalsprite”. Otherwise, a clone of the Bullet sprite may receive the “fire” message as well, which may generate a new duplicate clone.
The “shot info” attached to the “fire” message contains four pieces of information about the Player that has fired the shot: Player ID (“A” or “B”), x position, y position and direction. We store this information in four variables, then move the sprite to the given position/direction. Then, we make a clone of this sprite. Each clone is given a unique ID of two parts: the player ID (“A” or “B”), and a bullet ID that keeps increasing by 1.
24 - “Bullet” Sprite: Add clone to game
When a clone of the Bullet sprite is created, we first need to add it to the game. It will be dynamic since it will move forward in a straight line. It will be added as a circle with a diameter of 40, so the game server will use a 2D circle to represent it in the simulated game world.
After that, we need to make the bullet only hit the opponent player. For example, if the clone ID starts with “A”, then we set the bullet to collide only with Player sprites that has a clone ID of “B”. And when that happens, the bullet will destroy itself, and also send out a new message “bullet hit player”. This message will be handled by the Player sprite to reduce its health (to be discussed below).
Lastly, when the bullet hits a wall or the edge of the world, it will simply destroy itself.
25 - “Bullet” Sprite: When added to game
When we get a notification from the game server that a new Bullet clone has been added to the game, we add the 3D sphere to represent the Bullet in the 3D scene. There are a few steps we need to take:
- We will play an explosion sound.
- Depending on the clone ID starts with “A” or “B”, we add a sphere of red or black color to the scene. Its diameter should be 40, which matches the size we used to represent it at the game server. Again, you can think about it this way: if we look down from the top, the sphere looks like a circle on the ground with a diameter of 40.
- We move the sphere to the starting position, which is the position of the Player that fired the shot.
- We set a speed of 600 for this bullet to move along the starting direction.
26 - “Player” Sprite: Handle “bullet hit player”
When a bullet from the opponent hits a player, that player will receive a “bullet hit player” message. Only the main Player sprite on the user’s own computer will receive this message, not its replicate on the other computer. For example, when Player A got hit, only the Player on the host computer will receive this message. This avoid handling the message two times.
If the Player’s health is still greater than 0, we will reduce that player’s health by 1. Then we broadcast a “update health” message, and attach the clone ID and health of that player.
27 - “Player” Sprite: Handle “update health”
When the Player receives the “update health” message, we will make sure only the original sprite will handle it, not the clones. We do the following steps:
- Extract the player ID and the updated health value
- Use a repeat loop to go through the 3 rectangle labels that represent the health of that player, and set them to either green or black based on the health value
- If the health is already 0, then we send a message of “game over”, with the parameter being the ID of the opponent player. Note that this is the only way to end the game.
28 - “Winner” Sprite: Handle “game over”
When the “game over” message is received, we do the following in the “Winner” sprite:
- Hide the 3D scene, since we will use a 2D costume to show the end screen;
- Play a sound of “Success 7”
- Switch to the costume that shows the name of the winner: A or B
- After 3 seconds, we stop the entire program.
29 - “Powerup” Sprite: Handle the “add powerup” message
When the Powerup sprite receives the “add powerup” message, it will first make sure only the original sprite with clone ID of “originalsprite” will handle this message. Note that this is only done on the host computer, and whenever a new powerup sprite is added, it will be replicated on the guest computer.
The Powerup items can be either for gaining one health point or increasing the firepower by 1. You can fine-tune the parameters that control the type and frequency of the new powerup items based on your preference. Obviously, if there are too many “health” powerup items, then the game may never end, since both players can recover from hits quickly.
Here is how Powerup works currently:
- We wait a random time period between 30 to 60 seconds before adding each new powerup. You can make this time longer to reduce the number of powerups available.
- We pick a random position within the world
- We pick a random type between “health” or “firepower” with 50% probability for each. You can change the probabilities to generate more “health” or more “firepower” rewards.
- We move the sprite to the given position, then create a clone.
- Each clone has a unique ID composed of 2 parts: the powerup type and a sequence number.
30 - “Powerup” Sprite: When a clone is created at the host
When a new clone is created, we add it to the game as a static circle (diameter of 40) at the game server. After a random timeout period between 10 to 20 seconds, we remove this item from the game. This way, if the two players do not try to collect a powerup item quickly, it will disappear soon, making the game more exciting. Of course, if you change this time out period longer, it will become easier to gain power for both players.
30 - “Powerup” Sprite: When added to game
Similar to other sprites, we add the 3D object representing the powerup items under the block “when added to game”. This block is triggered on both computers when the host computer adds a new powerup item to the game.
We do the following to add the powerup item when it is added to the game:
- We play a sound to notify the users a new item has been added;
- We store the position of the item in 2 variables “my x” and “my y”. We need this because when we run the “add model” block, it will reset the sprite’s x and y positions to 0.
- We add the model for a medical box or a thunder icon depending on the Powerup type. Note that it is added as hidden, because otherwise the model will show up at the origin point before we move it;
- We will set a z-rotation to make it spin continuously forever.
- We will move the model to the saved position;
- Lastly, we show the object.
31 - “Player” Sprite: Handle “collect powerup”
When the Player sprite touches a Powerup object, it will trigger the “collect powerup” message. Only the Player clone that is controlled by the user will receive this message. To handle it, we first play a sound to confirm the collection of a Powerup. If it is a “health” type, and this player’s health is still less than 3, we would increase the health by 1, and broadcast the “update health” message, which updates the health value display at the top. Similarly, if this player’s firepower is less than 5, we increase it by 1, and send out the “update firepower” message.
32 - “Player” Sprite: Handle “update firepower”
The way we handle “update firepower” is very similar to how we handle “update health”. We extract the update firepower value from the message’s parameter, then we go through all 5 labels for that player, and set each label to red or black based on the firepower value.
Summary
We have explained all the blocks in this project. Feel free to try to remix and modify the game. Here are some ideas:
-
Adjust game parameters: There are many simple changes you can make to the game, such as player avatars, 3D models/textures used, maximum health/firepower values, time interval before each new Powerup is generated and how long it lasts, movement speed of the players and bullets, keyboard controls of the player movements, size/count/positon of the walls, size of the world, etc. Feel free to change them based on your preference.
-
New Powerup types: You can extend the game by adding new Powerup types, such as speed-up for player or bullet, new types of bullets (double or triple bullets), powerup to allow players to run through walls or see through the walls, etc.
-
2 vs 2 games: You can try to allow four users to play together. You will need to increase the game capacity when you create the game, and add new player IDs like “C” and “D”, etc.
-
AI Players: You can create an AI bot to control one player, so that one user can play against the AI instead of looking for another player, or you can have 2 human players team up to play against 2 AI players.
-
Virtual Joysticks for User Input
Introduciton
You can now add joystick-style user controls for your 3D games, which is a natural input method for users on touchpads and smartphones.
Note that this new feature only works in 3D projects, and a 3D scene must be initialized first.
Add a Joystick
A virtual joystick is made of 2 parts:
- A “base” that is composed of 2 circles. Whenever the pointer is pressed down, the base will not move as the pointer is dragged around it.
- A “puck” that is a smaller circle with a dot at its center. It shows the current position of the pointer relative to the base.
You can add a new joystick using the following block:
The inputs are:- Left or Right: you can add a left or right joystick using this block. The left one only covers the left half of the screen, and the right one only covers the right half. Use this block 2 times to add both joysticks.
- Color1 and Color2: These two color inputs control the colors of the base and the puck.
- Scale: This is a scaling factor that controls the size of the virtual joystick. By default, it is 100, which means 100% of the default size. If you would like to double the size of the joystick, you can set this value to 200.
Read joystick properties
You can read the properties of a joystick using this reporter block:
It has 2 inputs:- Side: left or right
- Property:
- x or y: the position of the puck relative to the center of the base. Note that both x and y are between -1 and 1. For example, if the puck is at the right edge of the base, then x will be 1 and y will be 0.
- dir: the direction of the puck relative to the base in degrees, which is between -180 and 180.
- Distance: the distance of the puck from the base between 0 and 1.
- pressed: whether the joystick is pressed down. 0 means not pressed down, and 1 means it is pressed down. This should be the first value to check, since if the joystick is not pressed down, then all the other properties are not valid.
Remove all joysticks
You can use this block to remove all the joysticks you have added so far:
Demo
In this demo program, we first add a 3D glass object, then add 2 virtual joysticks of different colors and scales. Then we enter a forever loop: whenever the left or right joystick is pressed down, we read its properties into a few variables, and also rotate the 3D glass based on the “dir” property:
Here is the project link: -
ChatGPT AI: A Quiz Writer (Difficulty: 3)
Introduction
You have learned how to use ChatGPT to build smart chatbots. However, it can be used in many other types of projects, and the interface does not have to be a chat window.
In this tutorial, you will learn to build a smart “quiz writer”. The user can specify any topic, then the program will use ChatGPT to help generate a quiz question and also evaluate the user’s answer. You will also practice building a simple app using buttons and textarea.
Step 1 - An Empty Project
Create a new project, and name it “ChatGPT- Quiz Writer”. Delete the sprite with the dog, and we will just use the “Empty1” sprite for coding.
Step 2 - The Topic Input
First, let’s add a label that says “Topic”, and an input textbox for the user to write the topic. We’ll name these 2 widgets “topiclabel” and “topicinput”.
They will look like this:
Step 3 - Move Widgets Using the “Widget Position” Tool
Now we need to move these 2 widgets to the top row of the stage window, so we can add other widgets below them. This can be easily done using the “Widget Position” tool like this:
You will find the X/Y/Width/Height values of the 2 blocks are automatically changed for us, so the next time you run the program, the widgets will directly appear in the new positions:
Of course, you can still change the position and size numbers manually at any time.
Step 4 - Add a “Go” Button
Next, we will add another button that says “Go”, which will tell ChatGPT to generate the quiz.
By default, the button will appear at the center. Please use the “Widget Position” tool to place it in the top right like this:
Your program should be similar to this afterward:
Step 5 - Add the Question Box
Now we need to add a big textbox to show the quiz generated by ChatGPT. It should allow multiple lines of text but does not allow any user input (“read-only”). Practice using the widget position tool to position this textbox.
Step 6 - 2 New Custom Blocks
Before we add more widgets, it looks like this stack of blocks may be getting too tall. Therefore, it is a good time to define 2 new custom blocks to help organize the program.
Please define 2 new blocks “add question widgets” and “add answer widgets”, and run them in the main stack. We will also move all the existing blocks into the definition of “add question widgets”.
Step 7 - 4 Answer Buttons
Now we will add blocks to add 4 buttons in the definition of “add answer widgets”. Their names are simply A/B/C/D.
They look like this:
Step 8 - The Feedback Box
When we click one of the 4 buttons, we will ask ChatGPT to tell us if we got it correctly. So we need to add another textbox at the bottom to show ChatGPT’s feedback. Please add it as multi-line and read-only.
Now the interface is ready:
Step 9 - Compose Request to ChatGPT
Suppose the user inputs a topic at the top, then clicks the “Go” button. At this point, we need to compose a request and send it to ChatGPT. The request should include what the user wrote as well. We can write our request first, then join it with the user’s input.
To store our request, we can define a variable “request”, and set its value when the “Go” button is clicked:
Step 10 - Send Request to ChatGPT in Streaming Mode
Now we are ready to let ChatGPT do the magic and give us a random question. To show the question as soon as possible, we will use the “streaming” mode. To allow a fairly complex question, we can set the max length to 400.
Also, this should be a new chat, since each time we click “Go”, we do not need ChatGPT to remember the previous questions. If we use the continue mode, then after a few questions, we will reach the token limit of ChatGPT, and have to restart.
We will need to make another new variable “question” to hold the question generated by ChatGPT.
Step 11 - Show the Question
Now we need to show the question as ChatGPT generates it. We will use a “repeat until” loop to keep updating the question box with the value of the “question” variable. You can copy the emoji for the checkmark here (may look different here from the CreatiCode playground):
Now we can test if ChatGPT will generate the question properly:
Step 12 - Handle User Answer
When the user clicks on one of the 4 answer buttons, we need to ask ChatGPT about it. To do that, define a new block named “check answer”, which takes the “answer” as input:
Now we can run this new block when the user clicks the 4 buttons:
Step 13 - Compose the Feedback Request
In the “check answer” block’s definition, we need to compose a new request to ChatGPT: we will tell ChatGPT what’s the question since we are not asking ChatGPT to remember it. We also need to tell it the user’s answer, then ask ChatGPT whether it is correct.
We can compose a 4-part request using the “join” block like this:
Step 14 - Display the Feedback from ChatGPT
The remaining work is very similar to how we get the question from ChatGPT. We send the request, then display the result in the “feedback” textbox. You can duplicate the previous blocks and make some changes to them:
Now we have a working version of the quiz writer!
Step 15 - Highlight the User’s Answer
To make our quiz writer easy to use, we need to improve the user interface a bit. The most important change is to highlight the answer selected by the user.
We can change that button’s background color when it is clicked like this:
Step 16 - Reset Button Colors
When the user generates a new quiz question, we need to reset the color of all the answer buttons back to unselected. We can do it when the “Go” button is clicked:
Step 17 - Testing
Finally, you need to do some more testing to make sure the user experience is smooth. Here is a final demo:
Step 18 - Further Improvements
This quiz writer is a very basic version. There are many areas where you can improve it. Here are some ideas for you to try:
-
Other Question Format: For example, you can change the question format from multiple-choice to short answers. The user would need to write the answer in another textbox.
-
Improve the Prompt: The current request we send to ChatGPT is very simple, so sometimes we may get strange answers from ChatGPT. For example, in this feedback, the answer is wrong, but ChatGPt still says “Great job!” because it is a “great question”. Try to improve the request to avoid such issues.
- Better Colors: You can change the text style/color and background color of all the widgets to make the interface look better.
- Keeping Track of Scores: You can help the user keep track of how many questions were asked, and how many were answered correctly.
- Pre-generated Questions: Sometimes you may not want to generate the questions on the fly, since you have no control over what ChatGPT may ask. If you have a fixed topic, then you can ask ChatGPT to generate 20 questions for you, and store these questions and their answers in a list or table. Then when the user runs the program, you can randomly select the question from your pool of questions.
-
-
Export variables to files or Import files
Introduction
For every variable in a project, you can write code to export it to a text file on the user’s computer, or import a file from the user’s computer into a variable. This is useful when you need to allow the user to save some data that can be used later. For example, when you program a game, you may want to allow the players to save their current progress into a file and reload it later.
Export a Variable
You can use the “export variable [VARIABLE NAME]” block to export the value of a variable to a text file. For example, when you run this program, a new file named “variable1” will be downloaded into the “Downloads” folder on the user’s computer, and its content will be “22”. Of course, you can store much more data in a variable, and it will all be saved into the file.
Import a File into a Variable
You can also import a file into a variable like this:
When the user runs this program, an “Open File” dialog window will pop up, and the user can select ANY file that ends with “.txt” or “.csv”. Note that the file name doesn’t have to be the same as the variable name. Once the user selects a file, that file’s content will be stored in the variable you specified. If the user has cancelled the dialog window without selecting any file, then the variable’s content will not be changed.
-
RE: Customizing Gradients
@106809-mygccs
Thanks for the suggestion. This is an interesting feature. We will research how to implement it.
-
2D - SDG 3 - Care Bots for Older Persons (Difficulty: 1)
Key Topics Covered
- Arrow blocks for moving
- Say Things
- Set or Change Sprite Size
- Paint Costumes
- Switch Costumes
- Broadcasting messages
- Hiding or showing sprites
Introduction
The SDGs are 17 goals adopted by the United Nations in 2015. They are a to-do list for everyone to work on together.
This tutorial is about the well-being of older persons, which is related to the 3rd goal of “good health and well-being”.
For people over 65 years old, many of them live alone at home. To take care of them, one solution is to use healthcare robots (“care bots”) in their home.
This project will show more people what care bots can do. Grandpa will ask a care bot named “Joy” to help him find his book, and the user will use the keyboard to control Joy to fetch the book.Step 1 - Remix a Template Project
First, please click this link to open the project template:
https://play.creaticode.com/projects/0b30ffc8fe2cf7e5928b868d
Click the “remix” button to make a remix project of your own. Note that you need to be signed in to do this. If you are not signed, please sign in first, then click the above link again to load the project.
This project contains 4 sprites:
- The “Grandpa” sprite is the person who needs Joy’s help to fetch things;
- The “Joy” care bot has 16 costumes for walking in all 4 directions;
- The “Room” sprite contains a simple costume of the walls;
- The “Object” sprite contains some commonly used objects that Grandpa might be looking for, such as a book or glasses.
Step 2 - Paint a Backdrop Color
First, please select the stage, and use a rectangle to cover the entire costume. Pick a color that’s different from the sprites.
Step 3 - Grandpa Calls for Help
When the project starts, Grandpa needs to tell Joy what he is looking for. You can use the “say” block to show his request on the screen, such as “Joy, where is my book?” Note that you need to add these 2 blocks in the “Grandpa” sprite:
Step 4 - The “Start” Message
After saying the request, Grandpa will “tell” the “Object” sprite to move to a random place on the stage. He can do so by broadcasting a “Start” message after the “say” block:
In the “Object” sprite, when it receives the “Start” message, it should go to a random position.
Step 5 - Hide and Show the Book
Instead of showing the book to move randomly, we should hide it at the beginning, then show it after it has moved to a new position.
Now the book will be hidden at first, then show up in a random position:
Step 6 - Joy Starts at the Center
Now let’s add some code to the “Joy” sprite. First of all, we would want Joy to always start at the center of the stage. This makes it easier for the player to get started.
Step 7 - Joy Walks to the Right
When the player presses the right arrow key on the keyboard, we would like to make Joy turn to the right. There are 4 costumes with Joy facing the right “R1”, “R2”, “R3” and “R4”. We will just use “R2” for now.
We also need to make Joy move to the right a little bit using the right arrow block.
Now each time we press the right arrow key, Joy will move a bit to the right:
Step 8 - Add the Other 3 Directions
The code blocks for moving in the other 3 directions are very similar. Please also add them to the Joy sprite:
Now we can move Joy to anywhere on the stage:
Step 9 - Restart If Touching the Walls
Currently, Joy can walk through the walls in the room. To make the game more interesting, we can make Joy go back to the center point when it touches any wall.
Now test it out by making Joy walk into a wall:
Step 10 - Add a “Well Done” Message
When the player successfully moved Joy to the book object, we need to show a message. Please add a new sprite named “Success”, and draw a success message. Here is an example:
Step 11 - Hide the “Success” Sprite on Start
At the beginning of the game, we should hide the “Success” sprite. Please add these blocks to that sprite’s code:
Step 12 - Show the “Success” Sprite
When the Joy sprite touches the book object, we need to show the “Success” sprite.
First, we need to broadcast a new message “success”, whenever the Joy sprite touches the “Object” sprite. These blocks should go into Joy’s code:
In the “Success” sprite, when we receive the “success” message, we should show this sprite, and also move it to the center of the screen:
Now our game is ready:
Next Steps
There are many ways you can extend this project. Here are some examples:
-
Draw a Different Room: You can replace the “Room” sprite’s costume with your own drawings.
-
Find 2 Objects: You can change Grandpa to ask the player to find 2 objects instead of just one. The success condition needs to be changed as well.
-
RE: Viewing Remixes
Good question. We will add a section showing remixes, similar to MIT Scratch.
-
Introduction to Widgets with the Label Widget
Prerequisite
Description
Widgets are GUI elements (e.g. labels or buttons) for displaying information and taking user inputs. They can be used in both 2D and 3D projects.
Let’s look at labels as the first example widget. They are often used when we need to show some information to the user.
Adding the Widget Extension
Here is how to add the widget extension
Adding a Label Widget
To add a new label, you can use the “add label” block:
Parameters
- Text on Label: You can write some text on the label, or leave it blank.
- Center Position: The x and y positions of the center point of the label.
- Size: The width and height of the label. Note that the label is limited to the stage window, which has a width of 480 and a height of 360.
- Widget Name: You need to assign a unique name to any widget you add, so that you can refer to it later using that name. If you use a name that is already used by another widget, that widget will be removed first.
Removing a Widget
You can remove any widget using the “remove widget” block:
Parameters
- Widget Name: You have to select a valid name of an existing widget from the list. Note that to populate this list, you have to run the block that adds the widget first.
Demo
In this screencast, we first add 2 labels “start label” and “stop label”, then remove the “stop label”. Note that the dropdown for removal is empty before the labels are added.
Removing All Widgets
In case you need to remove all the widgets, you can use this block:
Note that when the user clicks the green flag button, all widgets will be removed, so it is not necessary to use “remove all widgets” at the very beginning of your project.
-
RE: Robot?
@mathew139616-10db496a
It is pretty much dependant on the “real life things” you want to interact with. For example, there are a category of “smart devices” that support IoT (Internet of Things) protocols, and you can send commands to those devices. But that’s currently not our focus, as we are more focused on AI related capabilities for now.
-
AI - KNN Classifier for Diabetes (Difficulty: 4)
Key Topics Covered
Introduction
AI can be used to diagnose many common illnesses, which allows people to monitor their health continuously. In this tutorial, we will build a computer model that predicts whether a person has diabetes. We will be using the K-Nearest-Neighbor number classifier, which makes its decision based on other people similar to the target patient.
Step 1 - Download the Raw Data “diabetes.csv”
We will be using a public domain dataset from Kaggle. Kaggle is an online learning platform for machine learning and data science.
This dataset contains health data on 768 patients, and whether each patient is diagnosed with diabetes or not.
- Open this link: https://www.kaggle.com/datasets/mathchi/diabetes-data-set
- Scroll down the page, and click the download button, which should download a file named “diabetes.csv”:
Step 2 - Create A New Project
Now please create a new project named “KNN for Diabetes” on the CreatiCode playground, remove “Sprite1”, and rename the “Empty1” sprite as “Data”. We will use this sprite to hold all code for handling the dataset.
Step 3 - Upload the “Raw Data”
To work with the dataset we have downloaded, we first need to upload it into our project as a table.
Create a new table named “raw data”, then right-click on the table header in the stage, and select “import”. Find and select the “diabetes.csv” file you have downloaded. Usually, it is in your “Downloads” folder.
The “raw data” table should now contain 768 rows in 9 columns. Save the project now, so that this table will be stored as part of the project.
Step 4 - Review the “raw data” Table
Before we build any model, it is always a good idea to browse through the raw data. It will help us understand the data better, and also allow us to check if there is anything wrong with the data, such as missing values or incorrect values.
For example, if you scroll left to the first few columns, and scroll down to row 76, you should see some issues:
For row 76, the second column is 0. This is for “Glucose”, which is sugar in the blood. It should not be 0, which means the data is missing for this patient. Either they did not have a chance to measure the Glucose level for this patient, or they forgot to include it in the raw data.
Similarly, for row 79, column 3 is 0. This column is the blood pressure of the patient, which also should never be 0.
In later steps, we will skip such invalid rows to improve our model’s accuracy.
The last column of the raw data is “outcome”. It represents whether this patient is diagnosed with diabetes or not. Can you find any pattern in the data for diabetes patients? Such intuitions will be crucial for designing your classifier model.
Step 5 - Create the “known data” Table
Next, create a new table named “known data”. It will be used as the input table for the KNN classifier.
To keep our classifier model simple, let’s start with only 2 columns: the second column “glucose” and the sixth column “BMI”. We can use more columns later.
The new table “known data” will have 3 columns: “label”, “Glucose” and “BMI”. Note that the “label” column will be the “outcome” column from the raw data.
Although we can add these 3 columns manually, it is preferable to use a few blocks to do it, so that we can reset the table at any time point. Please make a new block named “prepare known data”, and add these blocks to its definition:
Make sure you select “known data” in the drop-down, not the “raw data” table. These blocks will remove all the columns first, so the table becomes completely empty with no rows and no columns. Then we add 3 columns at position 1/2/3.If you click this stack of blocks, they will change the “known data” table to this:
Step 6 - Copy data to the “known data” Table
Next, we will copy some raw data into the known data table. We are going to copy only the first 700 rows of the raw data to train our model, and use the remaining 68 rows to test our model.
We will use a for-loop to call the “add to table” block 700 times, and the variable “i” will represent the row number:
For each row in the raw data, we need to extract 3 values in the “outcome”, “glucose” and “bmi” columns. The row number will be the variable “i”. Note that when you drag the “item at row/column” blocks, because they are quite wide, you need to align the left tip of the block with the input box.
After running the “prepare known data” stack again, the “known data” table now has 700 rows, although only the first 100 rows are displayed:
Step 7 - Skip Invalid Rows
Since both “glucose” and “BMI” have to be greater than 0, we need to skip those rows with 0 values for one or both of these columns.
Now if we run this stack again, we see that the “known data” table has 685 rows instead of 700. In other words, 15 rows with some 0 values are ignored.
Step 8 - Create the “test data” Table
Next, we will prepare another table named “test data”. It will contain the remaining rows from the raw data table. They will be used for testing the accuracy of our classifier.
This table has to start with the same 3 columns as the known data table: “label”, “glucose” and “bmi”. The “label” column will be left empty, so that our classifier can write its prediction into this column. To make it easier to compare the prediction with the actual diagnosis, we will add a fourth column to the “test data” table called “truelabel”. This column will be ignored by the classifier, but we can use it to compare with the model output later.
We can define another block “prepare test data” like this:
Click on this new stack to add the 4 columns to the empty table:
Step 9 - Copy Data into the “test data” Table
The code to copy into the “test data” table is very similar to that of the “known data” table. The key difference is now we are reading the rows from 701 to 768, and also we are copying the outcome into the “truelabel” column, and leaving the “label” column empty. Don’t forget to select the “test data” table.
After running this stack again, the “test data” table should contain 67 rows (one row of raw data is skipped):
Note that the “label” column is left empty. After this step, our data tables are ready.
Step 10 - (Optional) Plot the Known Data
For an optional step, you can plot the data in the “known data” to gain some additional understanding. We can use a small dot to represent each patient, and use “red” dots for diabetes patients and “green” dots for other patients. Each dot can be represented by a small rectangle of width 2 and height 2, and border width of 0. Since each row only has 2 measurements, we can use “glucose” as the x position and “bmi” as the y position.
When we run this stack, we get a “cloud” of red and green dots.
We can observe that green dots are denser on the left, and red dots are denser on the right. That means if the “glucose” is larger, then it’s more likely this patient is diagnosed with diabetes.In addition, the green and red dots are mixed up in many areas, which means it would be somewhat difficult to use the nearest neighbors for classification.
Step 11 - Create the KNN Classifier
Now let’s create a new sprite named “model”, which will hold all the blocks related to our classifier model.
In this sprite, we will create a KNN classifier named “c”. To start simple, let’s just use the 3 nearest neighbors. That is, for each unknown patient, we will try to find 3 known patients with similar “glucose” and “bmi” measurements. If 2 or more of these 3 patients have diabetes, then predict the unknown patient also does.
Note that you need to select “known data” from the drop-down.
Step 12 - Predict Using the KNN Classifier
Next, let’s make some predictions using the classifier. Note that the “test data” table is selected, and we have chosen to show the 3 neighbors used for prediction:
Now if you click the green flag, the model will run the prediction and write the results into the “test data” table. Given the small amount of data, it should finish the task instantly. Take a look at the “test data” table. It should now contain data in the “label” column, and a new column named “neighbors” should be added automatically. For each row in the “test data”, this column contains 3 numbers, which are the row numbers of the 3 most similar patients in the “known data” table.
Step 13 - Calculate Model Accuracy
The accuracy of the classifier can be defined as the percent of test data that we have correctly predicted. Given that there are 67 rows in the “test data” table, we just need to count for how many rows the “label” given by the model matches with the “truelabel” from the raw data.
To do that, we can create a new variable “correct count”, and set it as 0 first. Then we go through each of the 67 rows in the “test data” table, and if we find the “label” value is the same as the “truelabel” value for that row, we add 1 to “correct count”. Lastly, we can divide the correct count by 67 to get the accuracy percentage.
You should get an accuracy of about 67%. In other words, for every 3 new patients, our model will classify 2 of them correctly on average.
Step 14 - Try with More Neighbors
To improve our classifier’s accuracy, we can try to use more neighbors, so that our classifier is not misled by a few “bad neighbors”.
For example, if we change the neighbor count from 3 to 13, the accuracy would jump from 67.1% to about 80.5%:
Further Improvements
The classifier we have built is relatively simple. You can try to improve its accuracy in a few ways:
-
Different Neighbor Count: Which neighbor count parameter would give us the highest accuracy?
-
Different Columns: Instead of using “Glucose” and “BMI”, would some other columns be more helpful? You can try to change or add columns to your known data and test data.
-
RE: What does the add 3d video plane block do and how to use?
Yes it is for using video as texture. However, youtube videos are not supported, since it is blocked by CORS of Youtube.
Instead, you can follow these steps to test it:
-
Find or create a mp4 video file (make sure it’s appropriate).
-
Share the file online. One easy way is to use the “My Files” tab in the “My Stuff” page: https://play.creaticode.com/mystuff/files
That page allows you to upload a file and copy its public URL.
- Use the video’s public URL in the video plane block like this:
It will look like this:
-
-
Database - Collection Creation/Removal
Introduction
Database blocks are used to store data on the CreatiCode server, which can be retrieved later.For example, suppose you are building an app that collects user inputs, similar to a Google Form. Any user can open your project, but when they input some data, that data can not be saved as part of the project, since they can not save your project. With the help of a database, your app can store the user’s input in the database. After all the users have submitted their data using the app, you can read all the data from the database and further process it.
Create a Collection
To use a database, you first need to create a collection. A collection is very similar to a table, with a few columns that describe what kind of data is stored, and many rows of actual data.To create a collection, open the “database” category, and click the “Make a Collection” button. You will need to give the collection a name, and then add one or more columns. For each column, you need to specify the name of that column and what type of data will be stored in that column (date, text or number).
Here is how to create a collection named “students” with 3 columns of “name”, “age” and “height”:
Note that after creating this collection, a dozen new blocks will appear to allow us to work with this collection.Also, you will see a “preview” of this new collection in the stage window. It will contain the 3 columns, but there is no data. After we add more data to the collection, the top few rows of that collection will be displayed in this preview.
A New Table is Also Created
When the “students” collection is created, a new table named “students_table” is created automatically. This table works the same way as any other table, but it has the same columns as the collection, so it can be used to add data to the collection or read from the collection.
You can turn on the display of this table using its checkbox like this:
Do not confuse this table with the collection preview. The “students_data” table is a real table: you can change it manually or use the blocks in the “table” category. The “preview” is a read-only display of the top few rows of data stored in the collection in the database.
A typical workflow is like this: you add some data to the table “students_data”, then you insert that data into the “students” collection, then you will see that data in the preview of that collection. See “Add Data to a Collection” below.
Change Collection Columns
After a collection is created, you can still make changes to it, such as changing the collection name or some column’s name, or adding/removing columns. To do that, right-click on the collection’s name, and select “Change collection”:
Note that when you change the columns of a collection, all existing data will be removed, so usually you should only make such changes before adding any actual data to it.
Delete a Collection
It is fairly straightforward to delete a collection. You can just right-click on the collection’s name and select the “delete” menu option:
Add Data to a Collection
To add some data into the “students” collection, we do not do it directly. Instead, we first add the new data into the “students_data” table, then insert data from that table into the collection.For example, we can first manually add 2 rows of data to the table:
Next, we can use the “insert” block in the “database” category to insert the data from the “students_data” table into the “students” collection:
Note that the preview of the “students” collection now shows 2 rows of data in there. Although they look the same as the 2 rows in the “students_data” table, they are stored in the database server, not as part of this project. This way, any user can open this project and use the “insert” block to add more data to the same collection without changing this project.