Created
September 28, 2015 21:17
-
-
Save master3395/edccc49762bd341f58af to your computer and use it in GitHub Desktop.
a ROBLOX implementation of the Snake game. MIT licensed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Create a LocalScript, paste this code in it, and parent it to StarterGui. | |
| wait(1/30) | |
| local camera = workspace.CurrentCamera | |
| local UserInputService = game:GetService("UserInputService") | |
| local REDRAW_INTERVAL = 1/12 -- every x-th of a second | |
| local LEFT = Enum.KeyCode.Left | |
| local RIGHT = Enum.KeyCode.Right | |
| local UP = Enum.KeyCode.Up | |
| local DOWN = Enum.KeyCode.Down | |
| local GRID_WIDTH = 32 | |
| local GRID_HEIGHT = 32 | |
| local SCORE = 0 | |
| -- Don't edit anything below this line | |
| print("Snake game running") | |
| game.Players.LocalPlayer.Character.Parent = nil | |
| camera.CameraType = "Scriptable" | |
| camera.CoordinateFrame = CFrame.new(Vector3.new((GRID_WIDTH/2)*4, 100, (GRID_HEIGHT/2)*4), Vector3.new((GRID_WIDTH/2)*4, 0, (GRID_HEIGHT/2)*4)) | |
| -- Low-level Util function for making parts | |
| function newPart(x,y, green) | |
| local p = Instance.new("Part") | |
| p.Name = (green and "snake_" or "berry_")..SCORE | |
| p.CFrame = CFrame.new(x * 4, 0, y * 4) | |
| p.FormFactor = "Custom" | |
| p.Size = Vector3.new(4, 4, 4) | |
| p.Anchored = true | |
| if green then | |
| p.BrickColor = BrickColor.new("Bright green") | |
| else | |
| p.BrickColor = BrickColor.new("Bright red") | |
| end | |
| p.Parent = workspace | |
| return p | |
| end | |
| local function makeGrid() | |
| for x = 0, GRID_WIDTH do | |
| for y = 0, GRID_HEIGHT do | |
| local p = newPart(x, y, false) | |
| p.Name = "bkg"..x.."."..y | |
| p.Size = Vector3.new(4,1,4) | |
| p.CFrame = CFrame.new(x*4, -5, y*4) | |
| p.BrickColor = BrickColor.new("Dark stone grey") | |
| end | |
| end | |
| end | |
| local snakeHead = {xPos=0,yPos=0,xDir=0,yDir=1} -- Linked list containing the snake and each part's coordinates | |
| local snakeParts = { snakeHead } -- List containing each snake part | |
| -- Berry coords, and if it is active or not | |
| local berryX, berryY = 0, 0 | |
| local berryActive = false | |
| local berryP = newPart(0,0, false) | |
| -- Creates a new snake node | |
| local function newSegment(head) | |
| local node = { } | |
| node.xPos = head.xPos | |
| node.yPos = head.yPos | |
| node.xDir = 0 | |
| node.yDir = 0 | |
| node.head = head | |
| node.p = newPart(head.xPos, head.yPos, true) | |
| head.tail = node | |
| snakeParts[#snakeParts+1] = node | |
| end | |
| -- Util function for checking snake collisions | |
| -- Returns true when the snake is colliding with itself | |
| local function checkSnakeCollisions() | |
| local node = snakeHead.tail | |
| local snakeFuturePos = { | |
| x = snakeHead.xPos + snakeHead.xDir, | |
| y = snakeHead.yPos + snakeHead.yDir, | |
| } | |
| while node do | |
| if node.xPos == snakeFuturePos.x and node.yPos == snakeFuturePos.y then | |
| -- We have a collision! | |
| return true | |
| end | |
| node = node.tail -- navigate to the 'tail' (i.e. the next snake node) | |
| end | |
| return false | |
| end | |
| -- Checks for berry collisions | |
| local function checkBerryCollisions() | |
| local node = snakeHead | |
| while node do | |
| if node.xPos == berryX and node.yPos == berryY then | |
| berryActive = false -- om nom nom nom | |
| berryP.Transparency = 1 -- nom om nom nom | |
| print("NEW SCORE:", SCORE + 1) | |
| SCORE = SCORE + 1 | |
| if node == snakeHead then | |
| while node.tail do -- navigate to the lastmost node | |
| node = node.tail | |
| end | |
| newSegment(node) | |
| end | |
| break | |
| end | |
| node = node.tail | |
| end | |
| end | |
| -- Gets raw input from UserInputService, and updates positions accordingly | |
| local function HandleInput() | |
| local x, y = snakeHead.xDir, snakeHead.yDir | |
| if UserInputService:IsKeyDown(LEFT) then | |
| x = 0 | |
| y = -1 | |
| elseif UserInputService:IsKeyDown(RIGHT) then | |
| x = 0 | |
| y = 1 | |
| elseif UserInputService:IsKeyDown(UP) then | |
| y = 0 | |
| x = 1 | |
| elseif UserInputService:IsKeyDown(DOWN) then | |
| y = 0 | |
| x = -1 | |
| end | |
| snakeHead.xDir = x | |
| snakeHead.yDir = y | |
| end | |
| -- Redraws the 'game' | |
| local function Redraw() | |
| -- Redraw the Snake | |
| local node = snakeHead | |
| while node do | |
| -- Update the node's position | |
| node.xPos = (node.xPos + node.xDir) % (GRID_WIDTH + 1) | |
| node.yPos = (node.yPos + node.yDir) % (GRID_HEIGHT + 1) | |
| -- Update it's direction (if possible) | |
| if node.head then | |
| local next = node.head | |
| local diffX = next.xPos - node.xPos | |
| local diffY = next.yPos - node.yPos | |
| node.xDir = diffX | |
| node.yDir = diffY | |
| end | |
| node.p.CFrame = CFrame.new( | |
| node.xPos * 4, | |
| 0, | |
| node.yPos * 4 | |
| ) | |
| node = node.tail | |
| end | |
| end | |
| snakeHead.p = newPart(0, 0, true) | |
| -- Game code | |
| makeGrid() | |
| local t = tick() | |
| local evt; evt = game:GetService("RunService").RenderStepped:connect(function() | |
| HandleInput() | |
| if tick() - t > REDRAW_INTERVAL then | |
| if not berryActive then | |
| berryX = math.random(GRID_WIDTH) | |
| berryY = math.random(GRID_HEIGHT) | |
| berryP.CFrame = CFrame.new( | |
| berryX * 4, | |
| 0, | |
| berryY * 4 | |
| ) | |
| berryP.Transparency = 0 | |
| berryActive = true | |
| end | |
| if checkSnakeCollisions() then | |
| evt:disconnect() | |
| print("You lost! Score:", SCORE) | |
| end | |
| checkBerryCollisions() | |
| Redraw() | |
| t = tick() | |
| end | |
| end) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
where does the game go to?
where does it "play"?
how can i make it inside of an frame