Create your first game with Vectarine
In this step-by-step guide, we’ll see how you can create your first game using Vectarine. This will be a PONG game, where you control a paddle to bounce a ball and try to score against an AI opponent.
This guide is made for beginners and doesn’t go into the details of Vectarine. If you are already familiar with programming and game development, you can take a guided tour of Vectarine to see how to use the different features of the engine.
Installing Visual Studio Code
Section titled “Installing Visual Studio Code”Vectarine uses Luau for scripting. Luau is a programming language that is great for beginners as it is easy to learn, while still being a powerful language used by professionals all over the world.
You can use any text or code editor to edit .luau files, but for the best experience, I recommend using Visual Studio Code.
Feel free to skip this step if you already have a code editor installed that you like and that is able to edit Luau.
Visual Studio Code can be extended with extensions using the Crate icon on the left side of the window.
I recommend installing the following extensions to make editing Luau easier, and having access to autocompletion:
- Luau Language Server: Provides autocompletion, type checking and error highlighting for Luau code. This is a must have as it shows you available functions and their documentation as you type.
- StyLua: A code formatter for Luau. It automatically formats your code when you save the file, making it more readable and consistent. This is less important than Luau Language Server, but it can be nice to have.
When both extensions are installed, your code should be colored, errors should be highlighted, and you will see function suggestions when you type a dot after a module name:
Installing Vectarine
Section titled “Installing Vectarine”To install Vectarine, you can run the following command in a terminal depending on your platform
How do I run a command in a terminal?
You need to open a Terminal application.
- On Windows, you can search for “Powershell” in the start menu.
- On Linux, you can search for “Terminal” in your applications.
- On Mac, you can search for “Terminal.app” in your Apps or in Spotlight.
A terminal looks like a black window with white text. You can type text in it and press
When a command is running, it can display (a lot of) text in the terminal to tell you what it is doing. It is a good idea to read the text to see if there are any errors or warnings.
Sometimes, a command asks you for input or confirmation. You can type your answer and press
You can copy and paste the command from this page into the terminal. On Linux, you might need to use
You need to use powershell, not cmd.exe
irm https://vectarineengine.com/install_win.ps1 | iexcurl -fsSL https://vectarineengine.com/install_linux.sh | shcurl -fsSL https://vectarineengine.com/install_mac.sh | shAlternatively, if you prefer, you can download Vectarine from Github. In that case, you need to download the zip file for your platform.
You can unzip it anywhere you like and run VectarineEditor executable to get started.
On MacOS, I get the message: “VectarineEditor.app” is damaged and can’t be opened, what should I do?
Congratulations! You have installed Vectarine! You can run it from the desktop shortcut on Windows, or from the Applications folder on MacOS. On Linux, you can run it from the terminal by typing ./VectarineEditor in the terminal.
Creating a new project
Section titled “Creating a new project”Now that we have installed everything, let’s make a game.
First, in the Vectarine editor, press Create a new project and select the location where you want to create your project.
Once you created your project, you will see a black screen with the vectarine logo and some (fake) loading text.
Then, you will see this screen:

The Resources window
Section titled “The Resources window”This is normal, as no code has been written yet. You can open the resources window from the tools menu or with Ctrl+2 to see the files of your project.

The window you opened is the “Resources” window. It shows you all the files in your project. You can use it to:
- Check if a file is missing, corrupted, or fails to load and see why in the “Status” column.
- Open your game folder in the file explorer
- Open your resources (images, sounds, scripts, etc…) in external editors (your preferred text editor, image editor, …) by clicking on the blue link.
How can I change my preferred text/image/sound editor program?
You can click on “Preferences” in the menu bar to open the preferences window. There, you can set your preferred text editor from the list.
For your preferred image or sound editor, you need to configure your OS to open the file type with your preferred program. This depends on your OS. On windows for example, you can right-click on a file, select “Open with” and then “Choose another app” to select your preferred program and set it as default.
By default, an empty project has only one resource, the main script, scripts/game.luau. game.luau is the first file loaded by any Vectarine game. Its job is to set up the game
and load all of the other files needed.
You can press on the blue link to open the script in your default luau editor. You can also open the game folder to open the .luau file manually.
Editing the code
Section titled “Editing the code”An empty game script looks like this:
const debug = require('@vectarine/debug')const graphics = require('@vectarine/graphics')const vec4 = require('@vectarine/vec4')const vec = require('@vectarine/vec')
-- Need help to get started?-- Read: https://github.com/vanyle/vectarine/blob/main/docs/user-manual.md-- The manual is available offline in the Help menu.
debug.print("Loaded.")
-- ... extra code to draw the message here ...
function Update(deltaTime: number) debug.fprint("Rendered in ", deltaTime, "sec")
if graphics.drawSplashScreenIfNeeded({ -- Put the resources that need to be loaded here. }, "Loading") then return end
fakeLoadingTimer.value = fakeLoadingTimer.value + deltaTime if fakeLoadingTimer.value < 4.0 then graphics.drawSplashScreen("Pretending to load...", fakeLoadingTimer.value / 4.0) return end
gettingStartedUi:draw({})endBefore explaining what all the code does, try to replace “gettingStartedUi:draw()” at line 31 with graphics.drawSplashScreen("Empty game", 0.0) and save the file.
You should see the change in the editor immediately without needing to restart the game.
The basics of Luau
Section titled “The basics of Luau”When your game is first loaded, the game.luau file is executed. Files ending with .luau contain Luau code that is executed to make your game work.
Code is read top to bottom and every line contains something for the computer to do, like a cooking recipe.
Code is organized into functions. Functions are reusable pieces of code that do useful things.
function functionName()
-- put content of the function here
endYou can call a function to run it by writing its name followed by parenthesis:
functionName()This will run the content of functionName. While you can write and call your own functions, Vectarine and Luau have a lot of functions to do all kinds of things useful for making games like drawing to the screen, playing sound, etc.
A simple example is the math.abs function which removes the sign of a number so math.abs(-3) is 3 and math.abs(1.2) is 1.2.
Inside code, you can add explanations that do nothing for the computer but are useful for you to understand and remember what the code does.
These explanation are preceded by -- and are called comments. You can write anything you want in comments, and they will be ignored by the computer.
-- Hello, I'm explaining the code below.As this is a tutorial, I will use a lot of comments to explain what is going on all of the time. To help you distinguish between comments and code, the comments are grayed out.
The Update function is then called every frame. This is where you put the code that needs to be executed continuously, like drawing your game.
Code outside of the Update function is executed once at the start of the game and can be used to initialize things.
When you save, Vectarine will reexecute your game.luau file to provide hot-reload.
-- We define a function named Update. Vectarine tries to call the function named Update every frame.function Update(deltaTime: number) -- This code is executed every frameendThis is the minimal vectarine game. It does nothing, but you can add code inside Update to draw things.
deltaTime is the time in seconds since the last frame. You can use it to make objects move at a consistent speed regardless of how fast the code is executed.
Modules
Section titled “Modules”Modules are packages of related functions. To get access to a module, you need to import it using the require function, like so:
const myModule = require("moduleName")-- To execute a function, you need to put parenthesis after its name.-- Inside these parenthesis, you can sometimes put arguments to give the function more information to do its job.myModule.functionInsideModule()myModule.functionWithArguments(1, 4, 5)Vectarine has many modules to do many things. The first modules we’ll see are the debug, graphics, vec and vec4 modules.
debugprovides functions for debugging your game.graphicsprovides function to draw on the screen.vecprovides functions to make and modify 2d vectorsvec4provides functions to make and modify 4d vectors, which are used to represent colors.
As the screen is 2D, a lot of graphics functions take 2d vectors called Vec2 as arguments to represent screen locations.
To be able to use a vectarine function, you first need to import the module that contains it using require("@vectarine/modulename"),
for example const debug = require("@vectarine/debug") to import the debug module.
However, to use a built-in Luau module, you don’t need to import anything. For example the math module is built-in and is thus always available. We
say that the math module is part of the Luau Standard Library. Other modules of the standard library include table, string or bit32.
require is another example of a function from the standard library, as it is always available without needing to import anything.
You can find the list of all built-in modules in the Luau Standard Library Reference.
The vectarine modules are not part of the standard library, so you need to import them using require to use them.
You can find the list of all vectarine modules and the functions they provide inside the luau-api folder of your project.
Reading the list of available functions and their documentation is a good way to learn what you can do with vectarine.
Using the debug module
Section titled “Using the debug module”This is a lot of theory, let’s how it works in practice. You can copy and paste the following code in your game.luau file and save it to see what it does:
-- We require the debug module to get access to its functionsconst debug = require("@vectarine/debug")
-- We call the print function from the debug module to display a message in the console.-- We give the message as an argument to the print function, which is a string.debug.print("Hello, vectarine!")
-- We define the Update function that is called every frame.function Update(deltaTime: number) -- We call the fprint function from the debug module to display a message in the console that is updated every frame. debug.fprint("This message is updated every frame. The deltaTime is: ", deltaTime) -- The print and fprint function can take as many arguments as you want and will display them.endYou can open the console from the tools menu or with Ctrl+1 to see the output of the debug module. You should see a black screen (as nothing is drawn yet) and this in the console:
Using the graphics module
Section titled “Using the graphics module”How, let’s see how to draw a circle on the screen using the graphics module. You can copy and paste the following code in your game.luau file and save it to see what it does:
-- We require the graphics, vec and vec4 modules to get access to their functionsconst vec = require("@vectarine/vec")const vec4 = require("@vectarine/vec4")const graphics = require("@vectarine/graphics")
function Update(deltaTime: number) -- We call the clear function from the graphics module to set the background color to white. graphics.clear(vec4.WHITE) -- We call the drawCircle function from the graphics module to draw a red circle at the center of the screen with a radius of 0.5 units. graphics.drawCircle(vec.V2(0, 0), 0.5, vec4.RED)endAn aside on variables
Section titled “An aside on variables”You can make a vector using the vec.V2 function like so:
-- Import the vec module to get access to the vec2 typeconst vec = require("@vectarine/vec")
-- Use the vec.V2 function to create a vector with x = 1 and y = 2, and put it in a variable named vlocal v = vec.V2(1, 2)We are using the local keyword to create a variable named v that contains the vector (1, 2). Variables are like boxes that contain values.
The local keyword and the const keywords are similar, but const variables cannot be changed after they are created, while local variables can be changed.
-- var contains the value 3local var = 3-- name contains the value "Joe"local name = "Joe"
-- var2 contains the value 5 because it is the result of adding 2 to 3.local var2 = var + 2-- You can modify the content of a variable by assigning it a new value like so:-- Now var contains the value 4 because we added 1 to it.var = var + 1When requiring a module, we put it into a variable to use all of its functions later which is why we also use the const keyword there.
Colors are represented as vec4 because they are made of a mix of red, green, blue and alpha (opacity).
The vec4 module contains a few default colors like vec4.WHITE and vec4.RED but you can also create your own colors with vec4.createColor(r, g, b, a) where r, g, b and a are numbers between 0 and 1.
Try to replace the code inside your project with this one, and save the file. You should see a red circle and a blue rectangle on a white background.
-- Import the graphics, vec and vec4 modules-- modules that start with @vectarine/ are built-in modules provided by Vectarineconst graphics = require("@vectarine/graphics")const vec = require("@vectarine/vec")const vec4 = require('@vectarine/vec4')
function Update(deltaTime: number) -- Set the background color to white using the clear function graphics.clear(vec4.WHITE)
-- Draw a red circle at the center of the screen (0,0) with a radius of 0.5 units (2 units is the width of the screen) graphics.drawCircle(vec.V2(0, 0), 0.5, vec4.RED)
local rectColor = vec4.createColor(0, 0, 1, 1) -- Create a blue color -- Draw a blue rectangle at the bottom right of the screen graphics.drawRect(vec.V2(0.7, -1), vec.V2(0.3, 0.3), rectColor)endWhen using Vectors:
(0,0)is the center of the screen.(-1,-1)is the bottom left of the screen.(-1,1)is the top left of the screen.(1,-1)is the bottom right of the screen.(1,1)is the top right of the screen.
The screen is 2x2 units.

Displaying a value to debug
Section titled “Displaying a value to debug”Sometimes, you have a variable, but you don’t know its content:
local score = mysteryFunction()To understand your program, it is useful to know the content of your variable. To do so, you can use the debug module to print the content of your variable to the console:
const debug = require("@vectarine/debug")
local score = mysteryFunction()debug.print("The score is: ", score)Global values and the watcher
Section titled “Global values and the watcher”You can create variables without using the local keyword. These variables are called global and can be accessed from any file in your project.
You can see the content of a global variable in the watcher tool, which you can open from the tools menu or with Ctrl+3.
You can search the variable to watch-for by name in the search bar and its value will be shown and updated in real-time.
Alternatively, you can use the persist module to create global variables.
const persist = require("@vectarine/persist")const debug = require("@vectarine/debug")
-- persist.onReload creates a global variable named "global_persisted".-- You can inspect it in the watcher tool by searching for "global_persisted".-- Global variables are persisted between hot-reloads and can be inspected in the watcher toollocal persisted = persist.onReload({ value = 0,}, "global_persisted")
-- Every time you edit the file and save, the time since the game was loaded will be displayed.-- You can hit Ctrl+R to perform a hard reload and reset this value to 0.debug.print(persisted.value)
function Update(deltaTime: number) persisted.value += deltaTimeendReading input from the player
Section titled “Reading input from the player”We’d like to react to player input to make our game interactive. The io module provides functions to read input from the player.
const io = require("@vectarine/io")const graphics = require("@vectarine/graphics")const vec4 = require("@vectarine/vec4")const vec = require("@vectarine/vec")
function Update(deltaTime: number) graphics.clear(vec4.WHITE)
-- Depending on if space is pressed, we draw a red or blue circle at the center of the screen if io.isKeyDown("Space") then graphics.drawCircle(vec.V2(0, 0), 0.5, vec4.RED) else graphics.drawCircle(vec.V2(0, 0), 0.5, vec4.BLUE) endendLet’s make this game!
Section titled “Let’s make this game!”With these 2 concepts: drawing on the screen and reading player input, we have everything we need to make a simple pong game!
We start by drawing a ball at the center of the screen.
We store the position and velocity of the ball in a variable named Ball.
We can access and update the position using Ball.position and the velocity using Ball.velocity.
For now, we only use the position to draw the ball, but we will use the velocity later to move the ball.
const debug = require("@vectarine/debug")const graphics = require("@vectarine/graphics")const vec4 = require("@vectarine/vec4")const vec = require("@vectarine/vec")
-- Initialize a ball variable with a position at the center of the screen and a velocity pointing to the top right.local Ball = { position = vec.V2(0, 0), velocity = vec.V2(1, 1.5),}
function Update(deltaTime: number) graphics.clear(vec4.WHITE) graphics.drawCircle(Ball.position, 0.1, vec4.RED)endTo move the ball, we change its position every frame by adding the velocity to it.
To avoid having the ball go off the screen, when its position is too high (bigger than 1 or smaller than -1), we change the velocity to make it go in the opposite direction.
You might notice that we don’t write Ball.position += Ball.velocity, but we scale it by deltaTime.
With no scaling, it means that a game running at 60 fps would move the ball faster than a game running at 30 fps, so the gameplay would change a lot depending on the hardware. We
don’t want that! So we multiply by deltaTime so that the movement is proportional to the time elapsed since the last frame.
const debug = require("@vectarine/debug")const graphics = require("@vectarine/graphics")const vec4 = require("@vectarine/vec4")const vec = require("@vectarine/vec")
local Ball = { position = vec.V2(0, 0), velocity = vec.V2(1, 1.5),}
function Update(deltaTime: number) graphics.clear(vec4.WHITE) graphics.drawCircle(Ball.position, 0.1, vec4.RED)
-- By adding the velocity to the position every frame, the ball will move in the direction of the velocity. Ball.position += Ball.velocity:scale(deltaTime)
-- We change the velocity when the ball hits the border of the screen to make it turn around. -- Every if is a condition representing a border of the screen. if Ball.position.y < -1 then -- The math.abs function returns the absolute value of a number, (the number without its sign) Ball.velocity.y = math.abs(Ball.velocity.y) end if Ball.position.y > 1 then Ball.velocity.y = -math.abs(Ball.velocity.y) end
if Ball.position.x < -1 then Ball.velocity.x = math.abs(Ball.velocity.x) end if Ball.position.x > 1 then Ball.velocity.x = -math.abs(Ball.velocity.x) endendWhen saving, Vectarine re-executes game.luau, which runs your initialization code and resets all variables, including the position of the ball.
To preserve the ball between saves, we can use the Persist module to store the ball position and velocity in a way that survives reloads.
Persisted values are made global and can be inspected with the watcher tool.
const persist = require("@vectarine/persist")const vec = require("@vectarine/vec")
-- You can wrap any variable initialization with persist.onReload to make it persist between reloads.local Ball = persist.onReload({ position = vec.V2(0, 0), velocity = vec.V2(1, 1.5),}, "ball")
--- The rest is unchangedconst graphics = require("@vectarine/graphics")const vec4 = require("@vectarine/vec4")const vec = require("@vectarine/vec")const io = require("@vectarine/io")const persist = require("@vectarine/persist")
local Ball = persist.onReload({ position = vec.V2(0, 0), velocity = vec.V2(1, 1.5),}, "ball")
local Player = persist.onReload({ position = 0,}, "Player")
local racketSize = 0.4
function Update(deltaTime: number) graphics.clear(vec4.WHITE) -- Drawing graphics.drawCircle(Ball.position, 0.1, vec4.RED) graphics.drawRect(vec.V2(-0.9, Player.position), vec.V2(0.1, racketSize))
-- Player input if io.isKeyDown("Up") then Player.position += deltaTime end if io.isKeyDown("Down") then Player.position -= deltaTime end
-- Ball code stays the sameendconst graphics = require("@vectarine/graphics")const vec4 = require("@vectarine/vec4")const vec = require("@vectarine/vec")const io = require("@vectarine/io")const persist = require("@vectarine/persist")
local Ball = persist.onReload({ position = vec.V2(0, 0), velocity = vec.V2(1, 1.5),}, "ball")
local Player = persist.onReload({ position = 0,}, "player")
local Opponent = persist.onReload({ position = 0,}, "opponent")
local racketSize = 0.4
function Update(deltaTime: number) graphics.clear(vec4.WHITE) -- Drawing graphics.drawCircle(Ball.position, 0.1, vec4.RED) graphics.drawRect(vec.V2(-0.9, Player.position), vec.V2(0.1, racketSize)) graphics.drawRect(vec.V2(0.8, Opponent.position), vec.V2(0.1, racketSize))
-- Player input stays the same
-- Opponent movement if Ball.position.y < Opponent.position + racketSize / 2 then Opponent.position -= deltaTime / 1.1 end if Ball.position.y > Opponent.position + racketSize / 2 then Opponent.position += deltaTime / 1.1 end
-- Ball code stays the sameendconst graphics = require("@vectarine/graphics")const vec4 = require("@vectarine/vec4")const vec = require("@vectarine/vec")const io = require("@vectarine/io")const persist = require("@vectarine/persist")
local Player = persist.onReload({ position = 0, score = 0,}, "player")
local Opponent = persist.onReload({ position = 0, score = 0,}, "opponent")
local Ball = persist.onReload({ position = vec.V2(0, 0), velocity = vec.V2(1, 1.5),}, "ball")
function resetBall() Ball.position = vec.V2(0, 0) Ball.velocity.y = math.random() * 2end
function Update(deltaTime: number) graphics.clear(vec4.WHITE) -- Drawing graphics.drawCircle(Ball.position, 0.1, vec4.RED) graphics.drawRect(vec.V2(-0.9, Player.position), vec.V2(0.1, racketSize)) graphics.drawRect(vec.V2(0.8, Opponent.position), vec.V2(0.1, racketSize))
-- Player input stays the same
-- Opponent movement stays the same
-- Physics Ball.position += Ball.velocity:scale(deltaTime) if Ball.position.y < -1 then Ball.velocity.y = math.abs(Ball.velocity.y) end if Ball.position.y > 1 then Ball.velocity.y = -math.abs(Ball.velocity.y) end
if Ball.position.x < -1 then Opponent.score += 1 resetBall() elseif Ball.position.x < -0.8 then if Ball.position.y > Player.position and Ball.position.y < Player.position + racketSize then Ball.velocity.x = math.abs(Ball.velocity.x) end end
if Ball.position.x > 1 then Player.score += 1 resetBall() elseif Ball.position.x > 0.8 then if Ball.position.y > Opponent.position and Ball.position.y < Opponent.position + racketSize then Ball.velocity.x = -math.abs(Ball.velocity.x) end endendWe can use the math.random() function to obtain a random number between 0 and 1. We use it to make the game more interesting.
const graphics = require("@vectarine/graphics")const vec4 = require("@vectarine/vec4")const vec = require("@vectarine/vec")const io = require("@vectarine/io")const persist = require("@vectarine/persist")const text = require("@vectarine/text")
local Ball = persist.onReload({ position = vec.V2(0, 0), velocity = vec.V2(1, 1.5),}, "ball")
local Player = persist.onReload({ position = 0, score = 0,}, "player")
local Opponent = persist.onReload({ position = 0, score = 0,}, "opponent")
local racketSize = 0.4
function resetBall() Ball.position = vec.V2(0, 0) Ball.velocity.y = math.random() * 2end
function Update(deltaTime: number) graphics.clear(vec4.WHITE) -- Drawing graphics.drawCircle(Ball.position, 0.1, vec4.RED) graphics.drawRect(vec.V2(-0.9, Player.position), vec.V2(0.1, racketSize)) graphics.drawRect(vec.V2(0.8, Opponent.position), vec.V2(0.1, racketSize))
local scoreText = Player.score .. " - " .. Opponent.score local measurements = text.font:measureText(scoreText, 0.2) text.font:drawText(scoreText, vec.V2(-measurements.width / 2, 0), 0.2)
-- Player input stays the same
-- Opponent movement stays the same
-- Physics Ball.position += Ball.velocity:scale(deltaTime) if Ball.position.y < -1 then Ball.velocity.y = math.abs(Ball.velocity.y) end if Ball.position.y > 1 then Ball.velocity.y = -math.abs(Ball.velocity.y) end
if Ball.position.x < -1 then Opponent.score += 1 -- <-- Increment opponent score when the ball goes out on the left resetBall() elseif Ball.position.x < -0.8 then if Ball.position.y > Player.position and Ball.position.y < Player.position + racketSize then Ball.velocity.x = math.abs(Ball.velocity.x) Ball.velocity.y = 2 * math.random() end end
if Ball.position.x > 1 then Player.score += 1 -- <-- Increment player score when the ball goes out on the right resetBall() elseif Ball.position.x > 0.8 then if Ball.position.y > Opponent.position and Ball.position.y < Opponent.position + racketSize then Ball.velocity.x = -math.abs(Ball.velocity.x) Ball.velocity.y = 2 * math.random() end endendFinal version
Section titled “Final version”In the end, the code looks like this:
const graphics = require("@vectarine/graphics")const vec4 = require("@vectarine/vec4")const vec = require("@vectarine/vec")const io = require("@vectarine/io")const persist = require("@vectarine/persist")const text = require("@vectarine/text")
local Ball = persist.onReload({ position = vec.V2(0, 0), velocity = vec.V2(1, 1.5),}, "ball")
local Player = persist.onReload({ position = 0, score = 0,}, "player")
local Opponent = persist.onReload({ position = 0, score = 0,}, "opponent")
local racketSize = 0.4
function resetBall() Ball.position = vec.V2(0, 0) Ball.velocity.y = math.random() * 2end
function Update(deltaTime: number) graphics.clear(vec4.WHITE) -- Drawing graphics.drawCircle(Ball.position, 0.1, vec4.RED) graphics.drawRect(vec.V2(-0.9, Player.position), vec.V2(0.1, racketSize)) graphics.drawRect(vec.V2(0.8, Opponent.position), vec.V2(0.1, racketSize))
local scoreText = Player.score .. " - " .. Opponent.score local measurements = text.font:measureText(scoreText, 0.2) text.font:drawText(scoreText, vec.V2(-measurements.width / 2, 0), 0.2)
-- Player input if io.isKeyDown("Up") then Player.position += deltaTime end if io.isKeyDown("Down") then Player.position -= deltaTime end
-- Opponent movement if Ball.position.y < Opponent.position + racketSize / 2 then Opponent.position -= deltaTime / 1.1 end if Ball.position.y > Opponent.position + racketSize / 2 then Opponent.position += deltaTime / 1.1 end
-- Physics Ball.position += Ball.velocity:scale(deltaTime) if Ball.position.y < -1 then Ball.velocity.y = math.abs(Ball.velocity.y) end if Ball.position.y > 1 then Ball.velocity.y = -math.abs(Ball.velocity.y) end
if Ball.position.x < -1 then Opponent.score += 1 resetBall() elseif Ball.position.x < -0.8 then if Ball.position.y > Player.position and Ball.position.y < Player.position + racketSize then Ball.velocity.x = math.abs(Ball.velocity.x) Ball.velocity.y = 2 * math.random() end end
if Ball.position.x > 1 then Player.score += 1 resetBall() elseif Ball.position.x > 0.8 then if Ball.position.y > Opponent.position and Ball.position.y < Opponent.position + racketSize then Ball.velocity.x = -math.abs(Ball.velocity.x) Ball.velocity.y = 2 * math.random() end endendYou now have a fully functional pong game! Congrats!
What’s next?
Section titled “What’s next?”Now that you know the basics of Vectarine, you can check the overview to see how to use the different features of the engine including playing sounds, the displaying images, using the physics engine, and much more! You can try to expand on this game by adding sound effects, power-ups, etc. or create a new game from scratch!
You can also check the luau-api folder of your project which has all the available functions of Vectarine with documentation and examples on how to use them.
