Please be gentle: Noob needs help
-
- Prole
- Posts: 7
- Joined: Mon Jul 16, 2012 12:49 pm
Please be gentle: Noob needs help
Hi everyone!
I hope someone is nice enough to help me; or rather hold my hand:
So basically I have no experience in game development or coding, except a brief session with Gamemaker a few years ago ( which doesn't ). Nevertheless I always wanted to try and hoped to teach myself some basics via the tutorials. But now I must confess that I was unable to find the answers I needed though I tried to implement some tips from very related problems, alas, to no avail.
What I want to do is very simple I think, yet I seem to fail at its execution, so I would like someone to basically tell me exactly what to do in for dummies terms.
And what would that be? you might ask. I have a static background, in front of that a hero who flies. I am happy (thanks hamsterwheel tutorial). But it looks rather undynamic so I thought to myself a few clouds going from right to left would give the implementation of movement. But I can't get it to work even after multiple tries T.T . I searched the forums for code to copy but it wouln't work. The wiki was no help for me either, as were the tutorial videos since I seem to be to dumb to implement the examples to my own usage. I know I need something along the lines of loops and math.random to create my scrolling effect, but as of now I'm pretty much done for.
So please excuse this wall of text and tell me how to make a scroller of multiple clouds randomly loop out of a picture of one cloud.
I'd appreciate it a lot. Thanks in advance!
And please excuse any errors since english is not my mothertongue.
I hope someone is nice enough to help me; or rather hold my hand:
So basically I have no experience in game development or coding, except a brief session with Gamemaker a few years ago ( which doesn't ). Nevertheless I always wanted to try and hoped to teach myself some basics via the tutorials. But now I must confess that I was unable to find the answers I needed though I tried to implement some tips from very related problems, alas, to no avail.
What I want to do is very simple I think, yet I seem to fail at its execution, so I would like someone to basically tell me exactly what to do in for dummies terms.
And what would that be? you might ask. I have a static background, in front of that a hero who flies. I am happy (thanks hamsterwheel tutorial). But it looks rather undynamic so I thought to myself a few clouds going from right to left would give the implementation of movement. But I can't get it to work even after multiple tries T.T . I searched the forums for code to copy but it wouln't work. The wiki was no help for me either, as were the tutorial videos since I seem to be to dumb to implement the examples to my own usage. I know I need something along the lines of loops and math.random to create my scrolling effect, but as of now I'm pretty much done for.
So please excuse this wall of text and tell me how to make a scroller of multiple clouds randomly loop out of a picture of one cloud.
I'd appreciate it a lot. Thanks in advance!
And please excuse any errors since english is not my mothertongue.
- Robin
- The Omniscient
- Posts: 6506
- Joined: Fri Feb 20, 2009 4:29 pm
- Location: The Netherlands
- Contact:
Re: Please be gentle: Noob needs help
Sure we can help you. It would be easier if you can upload what you already have, then we can build on that.
Help us help you: attach a .love.
-
- Prole
- Posts: 7
- Joined: Mon Jul 16, 2012 12:49 pm
Re: Please be gentle: Noob needs help
Sure no problem, but I don't think this will help you much since I tend to delete things that don't work and start anew. Hence why there is nothing to see in terms of loop. But here you go!
Code: Select all
-- Ovierun
-- Hamsterball Movement stuff
-- load and key functions
function love.load()
Ovie = love.graphics.newImage("Ovie.png")
Background = love.graphics.newImage("Background.png")
x = 25
y = 25
speed = 200
height = love.graphics.getHeight( )
width = love.graphics.getWidth( )
Cloud = love.graphics.newImage("box.png")
Clouds = {}
end
-- Ovie movement
function love.update(dt)
if love.keyboard.isDown("right") then
x = x + (speed * dt)
elseif love. keyboard. isDown ("left") then
x = x - (speed * dt)
end
if love.keyboard.isDown ("up") then
y = y - (speed * dt)
elseif love.keyboard.isDown ("down") then
y = y + (speed * dt)
end
--Cloud loop
--??????
end
function love.draw()
love.graphics.draw (Background)
love.graphics.draw (Ovie, x, y)
love.graphics.draw (Cloud, height/2, width/2)--positional test
end
- Robin
- The Omniscient
- Posts: 6506
- Joined: Fri Feb 20, 2009 4:29 pm
- Location: The Netherlands
- Contact:
Re: Please be gentle: Noob needs help
After the line that says Clouds = {}, I would do the following:
In love.update:
In love.draw:
Try it out
Code: Select all
cloudspeed = 50
for i = 1, 5 do -- or something like 10 or whatever
Clouds[i] = {x = math.random(0, width), y = math.random(0, height)}
end
Code: Select all
for i, cloud in ipairs(Clouds) do
cloud.x = cloud.x + cloudspeed * dt
end
Code: Select all
for i, cloud in ipairs(Clouds) do
love.graphics.draw(Cloud, cloud.x, cloud.y)
end
Help us help you: attach a .love.
-
- Prole
- Posts: 7
- Joined: Mon Jul 16, 2012 12:49 pm
Re: Please be gentle: Noob needs help
OMG Thank you so much! I was really frustrated with this since I planned on this to be the easy part. I will tweek it a little just to get a grasp of what is what and then onward to the real Problems.
Again: Thank you.
Again: Thank you.
Re: Please be gentle: Noob needs help
Here are some things to consider:
Storing and drawing a single cloud
Each cloud could be a table, having an x position, a y position, and an image. These values can then be used to draw the cloud.
Moving the cloud
The clouds x position can be subtracted from in love.update, making it move left. The speed it does this can also be stored in the cloud's table, in pixels-per-second.
To start the cloud at the right of the screen, we need to know the screen width, and set the initial x position to that.
The y position and speed of each cloud can be set to random numbers using math.random, which works like this:
A cloud generator
Let's make a function which returns a cloud in a random position, at a random speed. It will be useful to create multiple clouds.
(Notice the "local" before the cloud table in cloudGenerator? That means that the cloud variable won't be accessable outside that function. It's not needed, because it's returned.)
aNiceCloud is now exactly the same as the cloud table used in the previous example! But now with the cloud generator function, it's easy to create multiple clouds...
But, it could be easier!
Let's a make a table for all of the clouds. That way, they can all be updated and drawn at the same time.
clouds = {} creates the table, table.insert(clouds, cloudGenerator()) insert a generated cloud, and for _, cloud in ipairs(clouds) do loops over everything in clouds, with each element being referent to as "cloud".
Instead of having table.insert(clouds, cloudGenerator()) repeated, we could use another type of for loop (called a numeric for loop) to create them all, but you probably won't be creating all of them at the same time.
For more on for loops,
check this out.
Now, for a slight detour...
When, part 1: Getting something to happen after a certain time.
Here is one way of having something occur at a regular interval:
- Creating a variable to store the time (in seconds) at which to do something
- Subtracting "dt" from this variable every frame from love.update
- Checking to see if this variable has reached 0, and if so, doing some action
Here is an example of something happening after three seconds:
Or, for an example you can actually run...
When, part 2: Getting something to happen repeatedly after a certain time.
Now, let's say you want something to happen repeatedly, instead of just once.
To do this, you can reset your timer variable. You could set the timer back to the time at which to do something, but for more accuracy, you could set the timer to whatever the value of the current timer is (which may not be exactly, and add the time limit.
In the example below, a new "O" gets added every half a second.
When, part 3: Getting something to happen repeatedly after a random time.
Instead of the timer being set back to an exact number, you can use math.random to choose a random number.
For example, for something to happen at a random interval between 1 and 10 seconds...
Here is the example from before, but with random timing:
Creating clouds at random times
Everytime the timer reaches 0, we can insert a new cloud into the clouds
table.
Removing clouds which have moved off the screen
Once clouds have moved off the screen, they are still in memory and still being updated and drawn. To remove a cloud after it has gone off the screen, we can...
- Loop over the clouds table (using a reverse numeric for loop, because removing table elements while looping over the table with an ipairs loop can be hazardous).
- Check if it is off the screen, which is when the x position plus the width of the cloud (which is the width of the image of the cloud) is less than or equal to the x position of the right side of the screen (which is 0).
- Removing the element with table.remove.
To test that this is working, we can print the number of clouds to see if it's what we would expect.
Here is an explanation of what was added...
This is a numeric for loop. The first part of the for loop is the variable which will change, and its starting value.
The # operator returns the number of elements in a table. So #clouds is the number of clouds.
The second part of the for loop, 1, is the limit. After it gets past one, it will stop.
The third part, -1, means that i will be subtracted by one every time the for loop loops.
Individual clouds can be access by their number. For example, cloud[1] will be the first cloud.
getWidth() is a method that images have in LÖVE, and, well, it gets the width of the image!
table.remove removes the table element at the position which you give it as the second argument.
Different cloud images
Instead of having just one image, you can have a table of different images, and randomly choose from that table.
cloudImages[math.random(1, #cloudImages)]
This line selects a random number from 1 to the number of elements in cloudImages, and the uses that number as an index of cloudImages to select a random image.
Making things easier to read with functions
You can take all the stuff for updating and drawing clouds, and put them in functions.
Or, to make main.lua even easier to read, you can put all the cloud stuff in its own file with require! Notice there is no ".lua" extention when requiring files.
main.lua
clouds.lua
I hope this helps!
(I have been ninjaed! I hope you get something from this anyway! )
- How to store and draw the clouds
- How the clouds will move
- Where the cloud will be created
- When the cloud will be created
And, possibly, - What cloud will be created (if we have have multiple cloud images)
Storing and drawing a single cloud
Each cloud could be a table, having an x position, a y position, and an image. These values can then be used to draw the cloud.
Code: Select all
function love.load()
cloud = {
x = 500,
y = 200,
image = love.graphics.newImage('cloud.png')
}
end
function love.draw()
love.graphics.draw(cloud.image, cloud.x, cloud.y)
end
Moving the cloud
The clouds x position can be subtracted from in love.update, making it move left. The speed it does this can also be stored in the cloud's table, in pixels-per-second.
Code: Select all
function love.load()
cloud = {
x = 500,
y = 200,
speed = 100,
image = love.graphics.newImage('cloud.png')
}
end
function love.update(dt)
cloud.x = cloud.x - cloud.speed * dt
end
function love.draw()
love.graphics.draw(cloud.image, cloud.x, cloud.y)
end
Code: Select all
function love.load()
SCREEN_WIDTH = 800
cloud = {
x = SCREEN_WIDTH,
y = 200,
speed = 100,
image = love.graphics.newImage('cloud.png')
}
end
function love.update(dt)
cloud.x = cloud.x - cloud.speed * dt
end
function love.draw()
love.graphics.draw(cloud.image, cloud.x, cloud.y)
end
Code: Select all
randomNumber = math.random(minimumNumber, maximumNumber)
Code: Select all
function love.load()
SCREEN_WIDTH = 800
cloud = {
x = SCREEN_WIDTH,
y = math.random(-10, 500),
speed = math.random(75, 125),
image = love.graphics.newImage('cloud.png')
}
end
function love.update(dt)
cloud.x = cloud.x - cloud.speed * dt
end
function love.draw()
love.graphics.draw(cloud.image, cloud.x, cloud.y)
end
A cloud generator
Let's make a function which returns a cloud in a random position, at a random speed. It will be useful to create multiple clouds.
Code: Select all
function love.load()
SCREEN_WIDTH = 800
aNiceCloud = cloudGenerator()
end
function love.update(dt)
aNiceCloud.x = aNiceCloud.x - aNiceCloud.speed * dt
end
function love.draw()
love.graphics.draw(aNiceCloud.image, aNiceCloud.x, aNiceCloud.y)
end
function cloudGenerator()
local cloud = {
x = SCREEN_WIDTH,
y = math.random(-10, 500),
speed = math.random(75, 125),
image = love.graphics.newImage('cloud.png')
}
return cloud
end
aNiceCloud is now exactly the same as the cloud table used in the previous example! But now with the cloud generator function, it's easy to create multiple clouds...
Code: Select all
function love.load()
SCREEN_WIDTH = 800
aNiceCloud = cloudGenerator()
anotherCloud = cloudGenerator()
andAnother = cloudGenerator()
end
function love.update(dt)
aNiceCloud.x = aNiceCloud.x - aNiceCloud.speed * dt
anotherCloud.x = anotherCloud.x - anotherCloud.speed * dt
andAnother.x = andAnother.x - andAnother.speed * dt
end
function love.draw()
love.graphics.draw(aNiceCloud.image, aNiceCloud.x, aNiceCloud.y)
love.graphics.draw(anotherCloud.image, anotherCloud.x, anotherCloud.y)
love.graphics.draw(andAnother.image, andAnother.x, andAnother.y)
end
function cloudGenerator()
local cloud = {
x = SCREEN_WIDTH,
y = math.random(-10, 500),
speed = math.random(75, 125),
image = love.graphics.newImage('cloud.png')
}
return cloud
end
Let's a make a table for all of the clouds. That way, they can all be updated and drawn at the same time.
Code: Select all
function love.load()
SCREEN_WIDTH = 800
clouds = {}
table.insert(clouds, cloudGenerator())
table.insert(clouds, cloudGenerator())
table.insert(clouds, cloudGenerator())
table.insert(clouds, cloudGenerator())
table.insert(clouds, cloudGenerator())
end
function love.update(dt)
for _, cloud in ipairs(clouds) do
cloud.x = cloud.x - cloud.speed * dt
end
end
function love.draw()
for _, cloud in ipairs(clouds) do
love.graphics.draw(cloud.image, cloud.x, cloud.y)
end
end
function cloudGenerator()
local cloud = {
x = SCREEN_WIDTH,
y = math.random(-10, 500),
speed = math.random(75, 125),
image = love.graphics.newImage('cloud.png')
}
return cloud
end
Instead of having table.insert(clouds, cloudGenerator()) repeated, we could use another type of for loop (called a numeric for loop) to create them all, but you probably won't be creating all of them at the same time.
For more on for loops,
check this out.
Now, for a slight detour...
When, part 1: Getting something to happen after a certain time.
Here is one way of having something occur at a regular interval:
- Creating a variable to store the time (in seconds) at which to do something
- Subtracting "dt" from this variable every frame from love.update
- Checking to see if this variable has reached 0, and if so, doing some action
Here is an example of something happening after three seconds:
Code: Select all
function love.load()
timeToDoSomething = 3
timer = timeToDoSomething
end
function love.update(dt)
timer = timer - dt
if timer <= 0 then
-- Do something!
end
end
Code: Select all
function love.load()
timeToDisplayText = 3
timer = timeToDisplayText
text = '...'
end
function love.update(dt)
timer = timer - dt
if timer <= 0 then
text = 'WOO!'
end
end
function love.draw()
love.graphics.print(text, 10, 10)
end
When, part 2: Getting something to happen repeatedly after a certain time.
Now, let's say you want something to happen repeatedly, instead of just once.
To do this, you can reset your timer variable. You could set the timer back to the time at which to do something, but for more accuracy, you could set the timer to whatever the value of the current timer is (which may not be exactly, and add the time limit.
Code: Select all
function love.load()
timeToDoSomething = 3
timer = timeToDoSomething
end
function love.update(dt)
timer = timer - dt
if timer <= timeToDoSomething then
-- Do something
-- Reset the timer
timer = timer + timeToDoSomething
end
end
Code: Select all
function love.load()
timeToAddAnO = 0.5
timer = timeToAddAnO
numberOfOs = 2
end
function love.update(dt)
timer = timer - dt
if timer <= 0 then
numberOfOs = numberOfOs + 1
timer = timer + timeToAddAnO
end
end
function love.draw()
love.graphics.print('W'..string.rep('O', numberOfOs)..'!', 10, 10)
end
When, part 3: Getting something to happen repeatedly after a random time.
Instead of the timer being set back to an exact number, you can use math.random to choose a random number.
For example, for something to happen at a random interval between 1 and 10 seconds...
Code: Select all
function love.load()
timer = math.random(1, 10)
end
function love.update(dt)
timer = timer - dt
if timer <= timeToDoSomething then
-- Do something
-- Reset the timer
timer = timer + math.random(1, 10)
end
end
Code: Select all
function love.load()
minRandomTime = 0.1
maxRandomTime = 2
timeToAddAnO = math.random(minRandomTime, maxRandomTime)
timer = timeToAddAnO
numberOfOs = 2
end
function love.update(dt)
timer = timer - dt
if timer <= 0 then
numberOfOs = numberOfOs + 1
timer = math.random(minRandomTime, maxRandomTime)
end
end
function love.draw()
love.graphics.print('W'..string.rep('O', numberOfOs)..'!', 10, 10)
end
Creating clouds at random times
Everytime the timer reaches 0, we can insert a new cloud into the clouds
table.
Code: Select all
function love.load()
SCREEN_WIDTH = 800
minCloudGenerationTime = 0.2
maxCloudGenerationTime = 3
cloudTimer = math.random(minCloudGenerationTime, maxCloudGenerationTime)
clouds = {}
end
function love.update(dt)
for _, cloud in ipairs(clouds) do
cloud.x = cloud.x - cloud.speed * dt
end
cloudTimer = cloudTimer - dt
if cloudTimer <= 0 then
table.insert(clouds, cloudGenerator())
cloudTimer = math.random(minCloudGenerationTime, maxCloudGenerationTime)
end
end
function love.draw()
for _, cloud in ipairs(clouds) do
love.graphics.draw(cloud.image, cloud.x, cloud.y)
end
end
function cloudGenerator()
local cloud = {
x = SCREEN_WIDTH,
y = math.random(-10, 500),
speed = math.random(75, 125),
image = love.graphics.newImage('cloud.png')
}
return cloud
end
Removing clouds which have moved off the screen
Once clouds have moved off the screen, they are still in memory and still being updated and drawn. To remove a cloud after it has gone off the screen, we can...
- Loop over the clouds table (using a reverse numeric for loop, because removing table elements while looping over the table with an ipairs loop can be hazardous).
- Check if it is off the screen, which is when the x position plus the width of the cloud (which is the width of the image of the cloud) is less than or equal to the x position of the right side of the screen (which is 0).
- Removing the element with table.remove.
To test that this is working, we can print the number of clouds to see if it's what we would expect.
Code: Select all
function love.load()
SCREEN_WIDTH = 800
minCloudGenerationTime = 0.2
maxCloudGenerationTime = 3
cloudTimer = math.random(minCloudGenerationTime, maxCloudGenerationTime)
clouds = {}
end
function love.update(dt)
for _, cloud in ipairs(clouds) do
cloud.x = cloud.x - cloud.speed * dt
end
cloudTimer = cloudTimer - dt
if cloudTimer <= 0 then
table.insert(clouds, cloudGenerator())
cloudTimer = math.random(minCloudGenerationTime, maxCloudGenerationTime)
end
for i = #clouds, 1, -1 do
if clouds[i].x + clouds[i].image:getWidth() <= 0 then
table.remove(clouds, i)
end
end
end
function love.draw()
love.graphics.print('Clouds: ' .. #clouds, 10, 10)
for _, cloud in ipairs(clouds) do
love.graphics.draw(cloud.image, cloud.x, cloud.y)
end
end
function cloudGenerator()
local cloud = {
x = SCREEN_WIDTH,
y = math.random(-10, 500),
speed = math.random(75, 125),
image = love.graphics.newImage('cloud.png')
}
return cloud
end
Code: Select all
for i = #clouds, 1, -1 do
if clouds[i].x + clouds[i].image:getWidth() <= 0 then
table.remove(clouds, i)
end
end
The # operator returns the number of elements in a table. So #clouds is the number of clouds.
The second part of the for loop, 1, is the limit. After it gets past one, it will stop.
The third part, -1, means that i will be subtracted by one every time the for loop loops.
Individual clouds can be access by their number. For example, cloud[1] will be the first cloud.
getWidth() is a method that images have in LÖVE, and, well, it gets the width of the image!
table.remove removes the table element at the position which you give it as the second argument.
Different cloud images
Instead of having just one image, you can have a table of different images, and randomly choose from that table.
Code: Select all
function love.load()
SCREEN_WIDTH = 800
minCloudGenerationTime = 0.2
maxCloudGenerationTime = 3
cloudTimer = math.random(minCloudGenerationTime, maxCloudGenerationTime)
cloudImages = {
love.graphics.newImage('cloud1.png'),
love.graphics.newImage('cloud2.png'),
love.graphics.newImage('cloud3.png')
}
clouds = {}
end
function love.update(dt)
for _, cloud in ipairs(clouds) do
cloud.x = cloud.x - cloud.speed * dt
end
cloudTimer = cloudTimer - dt
if cloudTimer <= 0 then
table.insert(clouds, cloudGenerator())
cloudTimer = math.random(minCloudGenerationTime, maxCloudGenerationTime)
end
for i = #clouds, 1, -1 do
if clouds[i].x + clouds[i].image:getWidth() <= 0 then
table.remove(clouds, i)
end
end
end
function love.draw()
love.graphics.print('Clouds: ' .. #clouds, 10, 10)
for _, cloud in ipairs(clouds) do
love.graphics.draw(cloud.image, cloud.x, cloud.y)
end
end
function cloudGenerator()
local cloud = {
x = SCREEN_WIDTH,
y = math.random(-10, 500),
speed = math.random(75, 125),
image = cloudImages[math.random(1, #cloudImages)]
}
return cloud
end
This line selects a random number from 1 to the number of elements in cloudImages, and the uses that number as an index of cloudImages to select a random image.
Making things easier to read with functions
You can take all the stuff for updating and drawing clouds, and put them in functions.
Code: Select all
function love.load()
SCREEN_WIDTH = 800
loadClouds()
end
function love.update(dt)
updateClouds(dt)
end
function love.draw()
drawClouds()
end
function cloudGenerator()
local cloud = {
x = SCREEN_WIDTH,
y = math.random(-10, 500),
speed = math.random(75, 125),
image = cloudImages[math.random(1, #cloudImages)]
}
return cloud
end
function loadClouds()
minCloudGenerationTime = 0.2
maxCloudGenerationTime = 3
cloudTimer = math.random(minCloudGenerationTime, maxCloudGenerationTime)
cloudImages = {
love.graphics.newImage('cloud1.png'),
love.graphics.newImage('cloud2.png'),
love.graphics.newImage('cloud3.png')
}
clouds = {}
end
function updateClouds(dt)
for _, cloud in ipairs(clouds) do
cloud.x = cloud.x - cloud.speed * dt
end
cloudTimer = cloudTimer - dt
if cloudTimer <= 0 then
table.insert(clouds, cloudGenerator())
cloudTimer = math.random(minCloudGenerationTime, maxCloudGenerationTime)
end
for i = #clouds, 1, -1 do
if clouds[i].x + clouds[i].image:getWidth() <= 0 then
table.remove(clouds, i)
end
end
end
function drawClouds()
love.graphics.print('Clouds: ' .. #clouds, 10, 10)
for _, cloud in ipairs(clouds) do
love.graphics.draw(cloud.image, cloud.x, cloud.y)
end
end
main.lua
Code: Select all
require 'clouds'
function love.load()
SCREEN_WIDTH = 800
loadClouds()
end
function love.update(dt)
updateClouds(dt)
end
function love.draw()
drawClouds()
end
Code: Select all
function loadClouds()
minCloudGenerationTime = 0.2
maxCloudGenerationTime = 3
cloudTimer = math.random(minCloudGenerationTime, maxCloudGenerationTime)
cloudImages = {
love.graphics.newImage('cloud1.png'),
love.graphics.newImage('cloud2.png'),
love.graphics.newImage('cloud3.png')
}
clouds = {}
end
function cloudGenerator()
local cloud = {
x = SCREEN_WIDTH,
y = math.random(-10, 500),
speed = math.random(75, 125),
image = cloudImages[math.random(1, #cloudImages)]
}
return cloud
end
function updateClouds(dt)
for _, cloud in ipairs(clouds) do
cloud.x = cloud.x - cloud.speed * dt
end
cloudTimer = cloudTimer - dt
if cloudTimer <= 0 then
table.insert(clouds, cloudGenerator())
cloudTimer = math.random(minCloudGenerationTime, maxCloudGenerationTime)
end
for i = #clouds, 1, -1 do
if clouds[i].x + clouds[i].image:getWidth() <= 0 then
table.remove(clouds, i)
end
end
end
function drawClouds()
love.graphics.print('Clouds: ' .. #clouds, 10, 10)
for _, cloud in ipairs(clouds) do
love.graphics.draw(cloud.image, cloud.x, cloud.y)
end
end
(I have been ninjaed! I hope you get something from this anyway! )
Last edited by Santos on Mon Jul 16, 2012 6:36 pm, edited 1 time in total.
-
- Prole
- Posts: 7
- Joined: Mon Jul 16, 2012 12:49 pm
Re: Please be gentle: Noob needs help
Definitely. You take a lot of guesswork and random mistakes off of my shoulders. Great tutorial.
Edit:grammar
Edit:grammar
Thanks a lot
I was looking for something like this (I want to make a spaceship which shots an indeterminated number of bullets that disapear once they are out of the screen and apear when the user press certain button), nice!
Who is online
Users browsing this forum: Ahrefs [Bot] and 3 guests