How to make a roblox game 2D Pixlated (Pixel Platformer)

This tutorial is showing you how I made a Pixel platformer game!
Game here: [Pixle Platform [ 2D ] - Roblox]

BTW the game is still unfinished, since I have many other 2D pixelated project. But I am making a tutorial on it anyways!


First things first, you need to draw your 2D textures. I recommend using Pixilart, it’s free to use!

Website:
[Pixilart - Free online pixel art drawing tool]

If you don’t know how to draw pixelated objects then you should watch a tutorial on YouTube, I will also make tutorials on how to draw it soon.

Example of the textures

Layer Information

- 18x18 / Width x Height

Box
pixil-layer-3
pixil-layer-4
pixil-layer-5
pixil-layer-31
pixil-layer-37


One you’ve drawn all your textures, open Roblox studio and Create your Roblox game.

Step 1: Add a Folder into workspace and name it “Level 0”. Add a Folder inside of Level 0 and name that “Map”. Add a part inside of map and name its “Grass”
Thing

:Grass Part Properties:
- Size (4,4,4)
- Transparency = 1

Step 2: Inside your Grass part, add a SurfaceGui > Then add a ImageLabel inside the SurfaceGui.
Thing

:ImageLabel Properties:
- Size (1,01,0)
*- Image = “Your Image ID” * / Or My example one (rbxassetid://14768096169)
- ResampleMode = Pixelated
- ScaleType = Crop

Step 3: Do the same thing you did with your grass on all of your textures.

Step 4: Create your first level for your game, by place each part besides each other.


Creating the health system

pixil-layer-40
pixil-layer-39
pixil-layer-38

Step 1: add a ScreenGui into StarterGui and name it “Health”

Step 2: add a sound into the Health Gui and name it “Hurt”

Step 3: add a local script into the Health Gui and name it “HealthScript”

Step 4: Create 3 ImageLabels and each image label will be a heart.
Paste this into the HealthScript:

local player = game.Players.LocalPlayer

local Health = player:WaitForChild("DeathCounter")

Health.Changed:Connect(function()
	script.Parent.Hurt:Play()
	if Health.Value == 1 then
-- 3 lives
		script.Parent.Heart1.Image = "Your half heart Image ID" -- Half Heart
		script.Parent.Heart2.Image = "Your Full heart Image ID" -- Full Heart
		script.Parent.Heart3.Image = "Your Full heart Image ID"	-- Full Heart
	elseif Health.Value == 2 then
-- 2 lives
		script.Parent.Heart1.Image = "Your No heart Image ID" -- No Heart
		script.Parent.Heart2.Image = "Your half heart Image ID" -- Half Heart
		script.Parent.Heart3.Image = "Your Full heart Image ID" -- Full Heart
	elseif Health.Value == 3 then
-- 1 live
		script.Parent.Heart1.Image = "Your No heart Image ID"	-- No Heart
		script.Parent.Heart2.Image = "Your No heart Image ID" -- No Heart
		script.Parent.Heart3.Image = "Your half heart Image ID" -- Half Heart
	elseif Health.Value == 4 then
-- player died
		script.Parent.Heart1.Image = "Your No heart Image ID" -- No Heart
		script.Parent.Heart2.Image = "Your No heart Image ID" -- No Heart
		script.Parent.Heart3.Image = "Your No heart Image ID" -- No Heart
	end
end)

Thing


Spikes : Optional

pixil-frame-0 (1)

If you have spikes in your game then, add a script into the spike and copy and paste this code into a normal script.

script.Parent.Touched:Connect(function(hit)
	local humanoid = hit.Parent:FindFirstChildWhichIsA("Humanoid")
		
	if humanoid then
		hit.Parent:WaitForChild("Cube").BillboardGui.ImageLabel.ImageColor3 = Color3.new(1, 0, 0)
		humanoid.Health = humanoid.Health - 100
		wait(0.2)
		hit.Parent:WaitForChild("Cube").BillboardGui.ImageLabel.ImageColor3 = Color3.new(1, 1, 1)
		end
	
end)


Water script: Optional

pixil-layer-19

If you have water that is supposed to kill players on touch then copy and paste this code into a normal script.

script.Parent.Touched:Connect(function(hit)
	local humanoid = hit.Parent:FindFirstChildWhichIsA("Humanoid")
		
	if humanoid then
		hit.Parent:WaitForChild("Cube").BillboardGui.ImageLabel.ImageColor3 = Color3.new(1, 0, 0)
		humanoid.Health = humanoid.Health - 100
		wait(0.2)
		hit.Parent:WaitForChild("Cube").BillboardGui.ImageLabel.ImageColor3 = Color3.new(1, 1, 1)
		end
	
end)


Coin script: Optional

Coin

If you have coins in you platformer game then paste this code into a normal script.

function coinPickup(partTouching)
	local player = game.Players:GetPlayerFromCharacter(partTouching.Parent)
	if partTouching.Parent:FindFirstChild("Player") then
		player.leaderstats.Coins.Value = player.leaderstats.Coins.Value + 15
		game.SoundService["Collect coin"]:Play()
		script.Parent:Destroy()
	end
end

script.Parent.Touched:Connect(coinPickup)


Creating the player leaderstats (Only if your making coin grabs)

Step 1: Add a script into the ServerScriptService | Name it “leaderstats”

Paste this script into the leaderstats server script:

game.Players.PlayerAdded:Connect(function(player)
	local DeathCounter = Instance.new("IntValue") --- This counter will be used when finding if the player lost all their lives later.
	DeathCounter.Name = "DeathCounter"
	DeathCounter.Value = 0
	DeathCounter.Parent = player
	
	local leaderstats = Instance.new("Folder") --- This is the folder that will hold the player stats.
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local Coins = Instance.new("IntValue") --- This is the coins value for the coin script.
	Coins.Name = "Coins"
	Coins.Parent = leaderstats
	Coins.Value = 0
	
end)


Finding the players lives

Step 1: Add a script into ServerScriptService | Name it “Counter”
Paste this script into the Counter Script:

game.ReplicatedStorage:WaitForChild("PlayerDied").OnServerEvent:Connect(function(player)
	local DeathCounter = player:WaitForChild("DeathCounter")
	DeathCounter.Value = DeathCounter.Value + 1
end)

Step 2: Add a RemoteEvent into ReplicatedStorage | Name the RemoteEvent “PlayerDied”.

Thing

Step 3: Add a local script inside of PlayerCharacterScripts | Name it “PlayerDied”
Paste this code into the PlayerDied local script:

local player = game.Players.LocalPlayer
local counter = player:WaitForChild("DeathCounter")
counter.Changed:Connect(function()
	if counter.Value == 4 then
		player:Kick("You Lost All Your Lives")
	end
end)

Step 4: Add a local script inside of PlayerCharacterScripts | Name it “DeathChecker”
Paste this code into the DeathChecker local script:

local player = game.Players.LocalPlayer
local humanoid = script.Parent:WaitForChild(“Humanoid”)


while true do
	wait(1)
	if humanoid.Health == 0 then
		game.ReplicatedStorage:WaitForChild("PlayerDied"):FireServer()
	end
end


Making the camera for the game

Step 1: Add a local script into the StarterCharacterScripts | Name it “CameraHandler”.
Paste this code into the CameraHandler Script:

-- Services
local rS = game:GetService("RunService")
local tS = game:GetService("TweenService")

-- Variables
local camera = game.Workspace.CurrentCamera
local root = script.Parent:WaitForChild("HumanoidRootPart")
local cameraPart = Instance.new("Part")
local newPos

-- Script
cameraPart.Anchored = true
cameraPart.CanTouch = false
cameraPart.CanCollide = false
cameraPart.Transparency = 1
cameraPart.Parent = game.Workspace
cameraPart.CFrame = CFrame.lookAt(root.CFrame.Position + Vector3.new(0, 90, 90), root.Position)
cameraPart.Orientation = Vector3.new(0,180,0)

camera.CameraType = Enum.CameraType.Scriptable

rS.PostSimulation:Connect(function(dt)
	cameraPart.Position = cameraPart.Position:Lerp(root.Position + Vector3.new(0, 0, -35), dt * 7)-- You can adjust the speed and "smoothness" by increasing or decreasing the "0.8", just make sure its a value between 0 and 1
	camera.CFrame = cameraPart.CFrame -- camera.CFrame = cameraPart.CFrame -- Set the camera's CFrame to the part's Cframe AFTER you have moved the part, so the camera gets moved correctly
end)


Making the player movement for the game

Step 1: Add a local script into the StarterCharacterScript | Name it “PlayerControls”.
Paste this script into the PlayerControls script:

local UserInputService = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local humanoid = player.Character:FindFirstChildOfClass("Humanoid")
local Cube = player.Character:WaitForChild("Cube")
local HumanoidRootPart = player.Character:WaitForChild("HumanoidRootPart")
UserInputService.InputBegan:Connect(function(input, processed)
	
	
	if input.KeyCode == Enum.KeyCode.A then
		Cube.BillboardGui.ImageLabel.Image = "Your character walking left Image ID"
		
	end
			
	if input.KeyCode == Enum.KeyCode.D then
		Cube.BillboardGui.ImageLabel.Image = "Your character walking right Image ID"
	end
	
	if input.KeyCode == Enum.KeyCode.Space then
		script.Jump:Play()
		Cube.BillboardGui.ImageLabel.Image = "Your character jumping Image ID"
	end
	
end)

UserInputService.InputEnded:Connect(function(input, processed)
	local Cube = player.Character:WaitForChild("Cube")
	if input.KeyCode == Enum.KeyCode.A then
		Cube.BillboardGui.ImageLabel.Image = "Your character idle facing left Image ID"
	end

	if input.KeyCode == Enum.KeyCode.D then
		HumanoidRootPart.Attachment.ParticleEmitter.Rate = 0
		Cube.BillboardGui.ImageLabel.Image = "Your character idle facing right Image ID"
	end
	
	if input.KeyCode == Enum.KeyCode.Space then
		Cube.BillboardGui.ImageLabel.Image = "Your character idle Image ID"
	end
end)

Step 2: Find sound for jumping | put the sound inside the PlayerControls script | Name the sound “Jump”.

Thing


Creating the character for the PlayerControls script

Step 1: Add a rig into workspace using Rig Build | Name the rig “StarterPlayer”

Step 2: Add a part | Name the part “Cube” | Resize the cube to fit the rig’s torso.

Step 3: Weld the Cube to the HumanoidRootPart | Add a BillboardGui into the Cube.
BillboardGui Properties
- AlwaysOnTop = Enabled
Max Distance = 120 — This numbered depends on how far your camera is from the character.

Step 4: Add a ImageLabel to the BillboardGui | Change the Image Label to your Character’s Idle Texture.
ImageLabel Properties
Size = (1,01,0)
ResampleMode = Pixelated
ScaleType = Fit

Step 5: Disable AutoRotate in the HumanoidRootPart, This will stop the character from turning around. Change the Health and Max Health to 60.

Step 6: Select each part of the character and make the Transparency 1.

Thing


Making the Double Jump for the game (Optional)

Step 1: Add a local script into the StaterPlayerScripts | Name the local script “DoubleJump”
Paste this code into the Double Jump Script:

local UserInputService = game:GetService("UserInputService")
local localPlayer = game.Players.LocalPlayer
local character
local humanoid
local canDoubleJump = false
local hasDoubleJumped = false
local oldPower
local TIME_BETWEEN_JUMPS = 0.1 -- bigger numbers, makes the delay between clicking jump twice longer.
local DOUBLE_JUMP_POWER_MULTIPLIER = 1 -- bigger numbers, makes the player jump further
function onJumpRequest()
	if not character or not humanoid or not character:IsDescendantOf(workspace) or
		humanoid:GetState() == Enum.HumanoidStateType.Dead then
		return
	end

	if canDoubleJump and not hasDoubleJumped then
		hasDoubleJumped = true
		humanoid.JumpPower = oldPower * DOUBLE_JUMP_POWER_MULTIPLIER
		humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
	end
end
local function characterAdded(newCharacter)
	character = newCharacter
	humanoid = newCharacter:WaitForChild("Humanoid")
	hasDoubleJumped = false
	canDoubleJump = false
	oldPower = humanoid.JumpPower

	humanoid.StateChanged:connect(function(old, new)
		if new == Enum.HumanoidStateType.Landed then
			canDoubleJump = false
			hasDoubleJumped = false
			humanoid.JumpPower = oldPower
		elseif new == Enum.HumanoidStateType.Freefall then
			wait(TIME_BETWEEN_JUMPS)
			canDoubleJump = true
		end
	end)
end
if localPlayer.Character then
	characterAdded(localPlayer.Character)
end

localPlayer.CharacterAdded:connect(characterAdded)
UserInputService.JumpRequest:connect(onJumpRequest)


Making the Disabler for the game (Optional if you want to disable things like the leader board or backpack)

Add a script into StarterCharacterScripts | Name the script “Disable”.
Paste this code into the Disable script.

wait()

game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, false) --change this to false if you want to delete Player list the player Names That appear top right
game:GetService("StarterGui"):SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false) --change this to false to disable player backpack(and gear)
game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Health, false) --change this to false to delete players health bar
game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Chat, false) --change this to false to delete the chat 
game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.EmotesMenu, false) --change this to false to delete Emotes Menu(/e dance,/e point,/e wave etc.)
game.StarterGui:SetCore("ResetButtonCallback",false)


Making the Left and Right Controls

Step 1: Push play to test the game. | Go into the StarterPlayerScripts and find [ PlayerModule ] |

Step 2: Stop the Game and Copy and Paste the [ PlayerModule ] into | StarterPlayer > StarterPlayerScripts
We only need the player to walk Left and Right

Player Module Script:

--!nonstrict
--[[
	Keyboard Character Control - This module handles controlling your avatar from a keyboard

	2018 PlayerScripts Update - AllYourBlox
--]]

--[[ Roblox Services ]]--
local UserInputService = game:GetService("UserInputService")
local ContextActionService = game:GetService("ContextActionService")

--[[ Constants ]]--
local ZERO_VECTOR3 = Vector3.new(0,0,0)

--[[ The Module ]]--
local BaseCharacterController = require(script.Parent:WaitForChild("BaseCharacterController"))
local Keyboard = setmetatable({}, BaseCharacterController)
Keyboard.__index = Keyboard

function Keyboard.new(CONTROL_ACTION_PRIORITY)
	local self = setmetatable(BaseCharacterController.new() :: any, Keyboard)

	self.CONTROL_ACTION_PRIORITY = CONTROL_ACTION_PRIORITY

	self.textFocusReleasedConn = nil
	self.textFocusGainedConn = nil
	self.windowFocusReleasedConn = nil

	self.leftValue = 0
	self.rightValue = 0

	self.jumpEnabled = true

	return self
end

function Keyboard:Enable(enable: boolean)
	if not UserInputService.KeyboardEnabled then
		return false
	end

	if enable == self.enabled then
		-- Module is already in the state being requested. True is returned here since the module will be in the state
		-- expected by the code that follows the Enable() call. This makes more sense than returning false to indicate
		-- no action was necessary. False indicates failure to be in requested/expected state.
		return true
	end

	self.leftValue = 0
	self.rightValue = 0
	self.moveVector = ZERO_VECTOR3
	self.jumpRequested = false
	self:UpdateJump()

	if enable then
		self:BindContextActions()
		self:ConnectFocusEventListeners()
	else
		self:UnbindContextActions()
		self:DisconnectFocusEventListeners()
	end

	self.enabled = enable
	return true
end

function Keyboard:UpdateMovement(inputState)
	if inputState == Enum.UserInputState.Cancel then
		self.moveVector = ZERO_VECTOR3
	else
		self.moveVector = Vector3.new(self.leftValue + self.rightValue, 0)
	end
end

function Keyboard:UpdateJump()
	self.isJumping = self.jumpRequested
end

function Keyboard:BindContextActions()

	-- Note: In the previous version of this code, the movement values were not zeroed-out on UserInputState. Cancel, now they are,
	-- which fixes them from getting stuck on.
	-- We return ContextActionResult.Pass here for legacy reasons.
	-- Many games rely on gameProcessedEvent being false on UserInputService.InputBegan for these control actions.
	

	local handleMoveLeft = function(actionName, inputState, inputObject)
		self.leftValue = (inputState == Enum.UserInputState.Begin) and -1 or 0
		self:UpdateMovement(inputState)
		return Enum.ContextActionResult.Pass
	end

	local handleMoveRight = function(actionName, inputState, inputObject)
		self.rightValue = (inputState == Enum.UserInputState.Begin) and 1 or 0
		self:UpdateMovement(inputState)
		return Enum.ContextActionResult.Pass
	end

	local handleJumpAction = function(actionName, inputState, inputObject)
		self.jumpRequested = self.jumpEnabled and (inputState == Enum.UserInputState.Begin)
		self:UpdateJump()
		return Enum.ContextActionResult.Pass
	end

	-- TODO: Revert to KeyCode bindings so that in the future the abstraction layer from actual keys to
	-- movement direction is done in Lua
	ContextActionService:BindActionAtPriority("moveLeftAction", handleMoveLeft, false,
		self.CONTROL_ACTION_PRIORITY, Enum.PlayerActions.CharacterLeft)
	ContextActionService:BindActionAtPriority("moveRightAction", handleMoveRight, false,
		self.CONTROL_ACTION_PRIORITY, Enum.PlayerActions.CharacterRight)
	ContextActionService:BindActionAtPriority("jumpAction", handleJumpAction, false,
		self.CONTROL_ACTION_PRIORITY, Enum.PlayerActions.CharacterJump)
end

function Keyboard:UnbindContextActions()
	ContextActionService:UnbindAction("moveLeftAction")
	ContextActionService:UnbindAction("moveRightAction")
	ContextActionService:UnbindAction("jumpAction")
end

function Keyboard:ConnectFocusEventListeners()
	local function onFocusReleased()
		self.moveVector = ZERO_VECTOR3
		self.forwardValue  = 0
		self.backwardValue = 0
		self.leftValue = 0
		self.rightValue = 0
		self.jumpRequested = false
		self:UpdateJump()
	end

	local function onTextFocusGained(textboxFocused)
		self.jumpRequested = false
		self:UpdateJump()
	end

	self.textFocusReleasedConn = UserInputService.TextBoxFocusReleased:Connect(onFocusReleased)
	self.textFocusGainedConn = UserInputService.TextBoxFocused:Connect(onTextFocusGained)
	self.windowFocusReleasedConn = UserInputService.WindowFocused:Connect(onFocusReleased)
end

function Keyboard:DisconnectFocusEventListeners()
	if self.textFocusReleasedConn then
		self.textFocusReleasedConn:Disconnect()
		self.textFocusReleasedConn = nil
	end
	if self.textFocusGainedConn then
		self.textFocusGainedConn:Disconnect()
		self.textFocusGainedConn = nil
	end
	if self.windowFocusReleasedConn then
		self.windowFocusReleasedConn:Disconnect()
		self.windowFocusReleasedConn = nil
	end
end

return Keyboard


Making tools respawn when player dies (Because of the multiple lives)

Step 1: Add a script into the ServerScriptService | Name the script “ToolRespawn”
Paste this code into the ToolRespawn script:

local Players = game:GetService("Players")

local Tools = Instance.new("Folder")

Players.PlayerAdded:Connect(function(Player)
	Player.CharacterAdded:Connect(function(Character)
		local BackPack = Player.Backpack
		local Humanoid = Character:FindFirstChild("Humanoid")
		for _, V in pairs(Tools:GetChildren()) do
			V.Parent = Character
		end
		Humanoid.Died:Connect(function()
			if Character:FindFirstChildWhichIsA("Tool") then
				Character:FindFirstChildWhichIsA("Tool").Parent = Tools
			end
			for _, V in pairs(BackPack:GetDescendants()) do
				V.Parent = Character
			end
		end)
	end)
end)


Making the skybox into a plain color for the 2D look

Paste your plain color ID into each part of the skybox Image places OR use “rbxassetid://14782738683” – plain light blue color


Making the Enemys for the game

Thing

Step 1: Duplicate your character |Name it “Enemy” and change the ImageLabel Image inside the BillboardGui to your enemy texture.

Step 2: Add 2 parts and name them both “Point1” and “Point2”. These are the points the enemy will walk too.

Step 3: Add a script into the Enemy | Name the script “Tween”.
Paste this script into the Tween script:

while true do
	wait(3) -- how long it takes for the enemy to reach the point and wait a few seconds.
	script.Parent.Cube.BillboardGui.ImageLabel.Image = "rbxassetid://14770386142"
	script.Parent.Humanoid:MoveTo(script.Parent.Point1.Position)
	wait(3)
	script.Parent.Cube.BillboardGui.ImageLabel.Image = "rbxassetid://14770408023"
	script.Parent.Humanoid:MoveTo(script.Parent.Point2.Position)
end

Step 4: Add a script into the Enemy | Name the script “DamageScript”.
Paste this into the DamageScript:


local function damage(touched)
	if touched.Parent:FindFirstChild("Humanoid") then
		touched.Parent.Humanoid.Health = touched.Parent.Humanoid.Health - 100
	end
end

for key, object in pairs(script.Parent:GetChildren()) do
	if object:IsA("Part") or object:IsA("MeshPart") then
		object.Touched:Connect(damage)
	end
end


Making Checkpoints for the game

Flag2
Flag3
pixil-frame-0 (3)

Step 1: Add a Spawn point into workspace | Name it level2Spawn.

Step 2: Add 2 parts | Name these parts “Flag” and “FlagPole”
Thing
Step 3: Add a script into level2Spawn |Name it “Touch” |and paste this into it:

script.Parent.Touched:Connect(function(hit)
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	player.RespawnLocation = script.Parent
	wait(0.05)
	game.SoundService.Checkpoint:Play()
	script.Parent.AllowTeamChangeOnTouch = false
	script.Parent.Parent.FlagPole.SurfaceGui.ImageLabel.Image = "rbxassetid://14783690861"
	script.Parent.Parent.Flag:Destroy()
	script:Destroy()
end)

(Optional )Step 4: Add a script into the Flag |Name it “Tween”| and paste this into it:

while true do
	wait(0.3)
	script.Parent.SurfaceGui.ImageLabel.Image = "Your Flag Image 1 ID"
	wait(0.3)
	script.Parent.SurfaceGui.ImageLabel.Image = "Your Flag Image 2 ID"
end

Thing


Your all set! Decorate your platformer game however you want!


Notes:

If you want to make your game look like its inside of a computer, add scanlines and a border to the screen using imagelabels in StarterGui

If your images in Roblox studio are blurry just change the ResembledType in your Image to Pixlated.

When trying to make things interactive, use a BillboardGui but put it in StarterGui then Adornee it to a part. That will make the imagebutton interactable.

Don’t forget to add a forcefield to each Level so the player does not fall of the world while jumping.

If your trying to add clouds to the back of you level then you can use mine
“rbxassetid://14784535696” — ImageLabel Image ID
Clouds2

55 Likes

Okay I’m ngl I did not even read majority of the post but damn I might follow this tutorial in the future.

Maybe you could create a level making system and all that like Super Marvio World

6 Likes

Thanks for the idea! I will keep this in mind. :smile:

4 Likes

Dang, that’s very good tutorial. Unfortunately, I’m more like 3D player.

1 Like

This is just an easy way of making your game look 2D!

3 Likes

Yeah, you do like making 2D games or 3D?

I like making 3D games more, it is easier trying to make 3D games look 2D or making 3D games look Retro / PS1 styled graphics, which are my favorite style in games.

1 Like

so like minecraft. I mean 3D games with pixels look?
I think Godot Engine would be best for this. I wanna learn Godot someday.

2 Likes

Yes, like minecraft or an rpg! I already have the Godot Engine, it is harder than I expected and I have to learn GDScript (Similar to Python) which is a custom coding language that Godot made for the specific engine. I am still trying though! :smiley: :+1:

3 Likes

Ooo! Keep it doing! I do have already Godot Engine, but I’m holding these for now. I’m as beginner right now. Learning stuff. Right now I’m making my second draft of game.

1 Like

That’s awesome, the first idea I am going to try is to make a game kind of like puppet combo or chilla’s art.

3 Likes

Super cool, most excellent tutorial!

2 Likes

Is there a way to disable the image blurring effect on normal images that aren’t GUI elements?

1 Like

Cool, I like making 2D games more tho.

might make a terraria type game with this

Ive already creadted a custom map editor for my hex grid life rpg game. Ive been contemplating how to setup the game to separate itself from general games these days. I think the best aproach would be to make it functionally different. I mean for 1: my game is procedurally generated. I think converting it to entirely a 2d platformer, giving modders the ability to create content and recreate an experience similar to starbound would be exactly what it would need to step out away from the masses on roblox. This post just showed me that there is a demand for 2d platformers, and i know there is a huge void for starbound players. Im definitely going to bring starbound to roblox. :grin:

2 Likes

Definitely! 2D games have some audience on Roblox. Make sure you don’t get into any legal trouble though


I set this up in about 10 minutes.
a completely procedurally generated side scroller.

2 Likes

Do you think you could make the game uncopylocked? :sweat_smile:


I setup a cool little teleporter (inspiration from StarBound) to the planet’s surface :slight_smile: