PcoWSkbVqDnWTu_dm2ix
We use cookies on this site to enhance your user experience

Prerequisites Have completed Arcade Action - Creating a Top Down Camera
Lesson Time 10 - 20 minutes
Optional Handouts N/A
Learning Objectives
  • Use ServerStorage to create a single enemy that can be copied during game time
  • Apply for loops and random numbers to write a function to create enemies at random locations
  • Create a function using the Touched Event that makes the player respawn upon hitting an enemy
  • Now that players have a working ship, it’s time to add some randomly spawning enemies for players to dodge. Double-check the walls of your arena to make sure they don’t overlap with the baseplate. If the walls do overlap, enemies will try to spawn inside of the walls where they can’t be shot.

    Create the Enemy

    The first task is to create an enemy object to make multiple copies of within ServerStorage. ServerStorage is used to hold objects scripts can make copies of when needed.

    1. Inside of ServerStorage, add a Folder renamed Enemies.
    2. In the Enemies folder, add a Sphere part named EnemyBall.
    3. With EnemyBall selected, check CustomPhysicalProperties and set the Friction value to 0. This will let the balls slide around forever on the arena’s baseplate.
    4. In the Workspace, add a Folder named Enemies (the game will have two folders named Enemies). This folder will store all spawned enemies.

    Coding the Enemy Behavior

    Once again is the question of which type of script object to use. Enemies should appear the same to all players, and players shouldn’t be able to control them.

    1. In ServerScriptService add a new Script named EnemyHandler.

    Create the Variables

    Variables like how many enemies to spawn should be created as constant variables at the top of the script. This makes it easier to tweak the game later without rewriting a bunch of code. The script will need numeric constant values for each of the following:

    • Number of enemies
    • Size of a safe zone to make spawning a little safer
    • Max speed of the enemies
    • Amount of time a player has to wait until respawning

    You’ll also need a variable to get to ServerStorage to access the EnemyBall created earlier.

    1. In EnemyHandler, add a comment for the script and the variables discussed above.
    -- Randomly spawns the number of enemies set in ENEMY_COUNT
    
    
    local ENEMY_COUNT = 100
    local SAFE_ZONE_SIZE = 50
    local MAX_ENEMY_SPEED = 20
    local RESPAWN_DURATION = 3
    
    local ServerStorage = game:GetService("ServerStorage")

    Writing the Function to Spawn Enemies

    To create the number of enemies set in ENEMY_COUNT, the script will use a for loop. The for loop will go through all of the same code for each enemy until all enemies are created.

    1. Add a function named spawnEnemies() with a parameter named count for the number of enemies to spawn.
    -- Called to spawn enemies in the arena
    local function spawnEnemies(count)
    
    end
    1. Add a local variable for the baseplate’s size. It will be used to determine where to spawn the enemies.
    local function spawnEnemies(count)
    	local baseplateSize = workspace.Arena.Baseplate.Size
    end
    1. Add a For loop that will keep running until the right number of enemy copies are made.
    local function spawnEnemies(count)
    	local baseplateSize = workspace.Arena.Baseplate.Size
    
    	-- Loops until there are the amount of enemies set in ENEMY_COUNT
    	for i = 1, count do
    
    --Makes a copy of EnemyBall
    		local enemy = ServerStorage.Enemies.EnemyBall:Clone()
    		enemy.Parent = workspace.Enemies
    
    	
    	end
    end
    1. Inside the for loop, create a random starting place and a random speed for each enemy.
    
    local function spawnEnemies(count)
    	local baseplateSize = workspace.Arena.Baseplate.Size
    
    	-- Loops until there are the amount of enemies set in ENEMY_COUNT
    	for i = 1, count do
    		-- Makes a copy of EnemyBall
    		local enemy = ServerStorage.Enemies.EnemyBall:Clone()
    		enemy.Parent = workspace.Enemies
    		
    		-- Assign a random position in the arena
    		local randomX = math.random(baseplateSize.X / -2 - SAFE_ZONE_SIZE, baseplateSize.X / 2 + SAFE_ZONE_SIZE)
    		local randomZ = math.random(baseplateSize.Z / -2 - SAFE_ZONE_SIZE, baseplateSize.Z / 2 + SAFE_ZONE_SIZE)
    		enemy.Position = Vector3.new(randomX , 9, randomZ)
    
    -- Assigns a random velocity to EnemyBall
    		local randomVX = math.random(-1 * MAX_ENEMY_SPEED, MAX_ENEMY_SPEED)
    		local randomVZ = math.random(-1 * MAX_ENEMY_SPEED, MAX_ENEMY_SPEED)
    		enemy.Velocity = Vector3.new(randomVX, 0, randomVZ)
    	end
    end
    
    1. Call the spawnEnemies() function at the very end of the script, using ENEMY_COUNT as a parameter.
    -- Have enemies spawn on the baseplate
    spawnEnemies(ENEMY_COUNT)
    
    -- Randomly spawns the number of enemies set in ENEMY_COUNT
    
    local ENEMY_COUNT = 100
    local SAFE_ZONE_SIZE = 50
    local MAX_ENEMY_SPEED = 20
    local RESPAWN_DURATION = 3
    
    local ServerStorage = game:GetService("ServerStorage")
    
    local function spawnEnemies(count)
    	local baseplateSize = workspace.Arena.Baseplate.Size
    
    	-- Loops until there are the amount of enemies set in ENEMY_COUNT
    	for i = 1, count do
    		-- Makes a copy of EnemyBall
    		local enemy = ServerStorage.Enemies.EnemyBall:Clone()
    		enemy.Parent = workspace.Enemies
    		
    		-- Places EnemyBall randomly on the baseplate
    		local randomX = math.random(baseplateSize.X / -2 - SAFE_ZONE_SIZE, baseplateSize.X / 2 + SAFE_ZONE_SIZE)
    		local randomZ = math.random(baseplateSize.Z / -2 - SAFE_ZONE_SIZE, baseplateSize.Z / 2 + SAFE_ZONE_SIZE)
    		enemy.Position = Vector3.new(randomX , 9, randomZ)
    		
    		-- Assigns a random velocity to EnemyBall
    		local randomVX = math.random(-1 * MAX_ENEMY_SPEED, MAX_ENEMY_SPEED)
    		local randomVZ = math.random(-1 * MAX_ENEMY_SPEED, MAX_ENEMY_SPEED)
    		enemy.Velocity = Vector3.new(randomVX, 0, randomVZ)
    	end
    end
    
    -- Have enemies spawn on the baseplate
    spawnEnemies(ENEMY_COUNT)
    

    Enemy and Player Collisions

    While enemies are created in the game, they don’t do anything to the player. To give players a challenge, every time they hit an enemy, their character will explode and be taken out of the game for a short time.

    Check if Player Hit an Enemy

    1. In the same EnemyHandler script, above spawnEnemies(), add a function named onTouched(), with an parameter named other. The other part is what touched the enemy.
    -- This is fired every time as enemy touches another part
    local function onTouched(other)
    
    end
    
    1. Check if the other part is one of the parts in the player’s ship.
    local function onTouched(other)
        if other.Name == "HumanoidRootPart" or other.Name == "Blaster" then
    
        end
    end
    

    Make the Player Respawn

    Within the if statement, code what should happen to any player that is found touching an enemy.

    1. Create a local variable to store the parent of the other part.
    local function onTouched(other)
        if other.Name == "HumanoidRootPart" or other.Name == "Blaster" then
            local character = other.Parent
        end
    end
    
    1. Move the player character to ReplicatedStorage to temporarily take them out of the game.
    local function onTouched(other)
    	if other.Name == "HumanoidRootPart" or other.Name == "Blaster" then
    		local character = other.Parent
    		-- Hide the player during the explosion
    		character.Parent = game:GetService("ReplicatedStorage")
    	end
    end
    
    1. Spawn an Explosion where the player was.
    character.Parent = game:GetService("ReplicatedStorage")
    -- Fire explosion where the player was
    local explosion = Instance.new('Explosion', workspace)
    explosion.Position = character:GetPrimaryPartCFrame().p
    
    1. After creating the explosion, make the player wait to be respawned for the amount of time set in RESPAWN_DURATION at the top of the script.
    local explosion = Instance.new('Explosion', workspace)
    explosion.Position = character:GetPrimaryPartCFrame().p
    
    wait(RESPAWN_DURATION)
    
    1. After the wait(), bring the character back into the game workspace and stop their previous movement entirely.
    wait(RESPAWN_DURATION)
    
    -- Reveal the character after they are knocked out and stop their movement
    character.Parent = workspace
    character.HumanoidRootPart.Velocity = Vector3.new(0,0,0)
    character.HumanoidRootPart.VectorForce.Force = Vector3.new(0,0,0)
    

    Finish the Code

    Go back to the for loop where you created the directions for spawning enemies. The collision code needs to connect to the Enemy’s Touch event.

    1. In the spawnEnemies() function, after enemy.Velocity, connect the onTouched() function to the enemy’s Touched event.
    local function spawnEnemies(count)
    	local baseplateSize = workspace.Arena.Baseplate.Size
    
    	-- Loop until we have as many enemy as we want
    	for i = 1, count do
    		-- Clone our default enemy
    		local enemy = ServerStorage.Enemies.EnemyBall:Clone()
    		enemy.Parent = workspace.Enemies
    		
    		-- Assign a random position in the arena
    		local randomX = math.random(baseplateSize.X / -2 - SAFE_ZONE_SIZE, baseplateSize.X / 2 + SAFE_ZONE_SIZE)
    		local randomZ = math.random(baseplateSize.Z / -2 - SAFE_ZONE_SIZE, baseplateSize.Z / 2 + SAFE_ZONE_SIZE)
    		enemy.Position = Vector3.new(randomX , 9, randomZ)
    		
    		-- Assign a random velocity to the enemy
    		local randomVX = math.random(-1 * MAX_ENEMY_SPEED, MAX_ENEMY_SPEED)
    		local randomVZ = math.random(-1 * MAX_ENEMY_SPEED, MAX_ENEMY_SPEED)
    		enemy.Velocity = Vector3.new(randomVX, 0, randomVZ)
    		
    		-- Make sure every time the enemy hits something,
    		-- it will check if it hit the player
    		enemy.Touched:Connect(onTouched)
    	end
    end
    
    
    1. Playtest your game to make sure the explosion is working. If the RESPAWN_DURATION feels too long, change the constant’s value at the top of the script. If the initial enemy count feels too low, you can change that too!
    -- Randomly spawns the number of enemies set in ENEMY_COUNT
    
    local ENEMY_COUNT = 100
    local SAFE_ZONE_SIZE = 50
    local MAX_ENEMY_SPEED = 20
    local RESPAWN_DURATION = 3
    
    local ServerStorage = game:GetService("ServerStorage")
    
    local function onTouched(other)
    	if other.Name == "HumanoidRootPart" or other.Name == "Blaster" then
    		local character = other.Parent
    		character.Parent = game:GetService("ReplicatedStorage")
    		
    		local explosion = Instance.new("Explosion", workspace)
    		explosion.Position = character:GetPrimaryPartCFrame().p
    		
    		wait(RESPAWN_DURATION)
    		
    		-- Reveal the character after they are knocked out and stop their movement
    		character.Parent = workspace
    		character.HumanoidRootPart.Velocity = Vector3.new(0,0,0)
    		character.HumanoidRootPart.VectorForce.Force = Vector3.new(0,0,0)
    	end
    end
    
    local function spawnEnemies(count)
    	local baseplateSize = workspace.Arena.Baseplate.Size
    
    	-- Loops until there are the amount of enemies set in ENEMY_COUNT
    	for i = 1, count do
    		-- Makes a copy of EnemyBall
    		local enemy = ServerStorage.Enemies.EnemyBall:Clone()
    		enemy.Parent = workspace.Enemies
    		
    		-- Places EnemyBall randomly on the baseplate
    		local randomX = math.random(baseplateSize.X / -2 - SAFE_ZONE_SIZE, baseplateSize.X / 2 + SAFE_ZONE_SIZE)
    		local randomZ = math.random(baseplateSize.Z / -2 - SAFE_ZONE_SIZE, baseplateSize.Z / 2 + SAFE_ZONE_SIZE)
    		enemy.Position = Vector3.new(randomX , 9, randomZ)
    		
    		-- Assigns a random velocity to EnemyBall
    		local randomVX = math.random(-1 * MAX_ENEMY_SPEED, MAX_ENEMY_SPEED)
    		local randomVZ = math.random(-1 * MAX_ENEMY_SPEED, MAX_ENEMY_SPEED)
    		enemy.Velocity = Vector3.new(randomVX, 0, randomVZ)
    		
    		enemy.Touched:Connect(onTouched)
    	end
    end
    
    spawnEnemies(ENEMY_COUNT)


    These documents are licensed by Roblox Corporation under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Roblox, Powering Imagination, and Robux are trademarks of Roblox Corporation, registered in the United States and other countries.


    Previous Creating a Top-Down Camera Next Ship Blasters