Author Topic: Level design/ Code questions from a beginner  (Read 16091 times)

0 Members and 1 Guest are viewing this topic.

AWS

  • Achiever
  • Arboreal Being
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 274
Level design/ Code questions from a beginner
« on: April 04, 2010, 02:30:40 PM »
hi all,
first things first...im a complete beginner and these are my Q's to annikk.exe, and now everyone whose interested, about the real basics of making a level. i hope it helps anyone else interested in doing so, answer some of the more basic elements of design.

this is a continuation of some correspondence between myself and anikk.exe about my attempts at a first level, of anything, ever!
im moving it over from PM to public thread so everyone can see what ive been asking, running into, and the helpful solutions being given.
everyone and anyone please feel free to add their own take on things.
ill be adding to this thread whenever i hit any problems/ questions/ etc about why my code isn't working or what i would like to achieve with my level and what is needed to do it.

as i said, this is all very new to me so please excuse my ignorance.

My initial questions were 2;

---

Q1-the more important one relates to the win conditions. in your example, you set the condition that a certain asteroid has to be taken to win. however, i want to make a level where every asteroid has to be taken, not just a certain one, and i cant figure out how to change the code accordingly.

Reply -
Hmm, I guess what I would do is skip the function OnAsteroidTaken section entirely (delete or comment it out), and instead create a loop in your function LevelLogic() as follows:

Code:

while GameRunning() do

if GetEmpire(1):GetNumOwnedAsteroids() == 99999 then
Pause()
MessageBox("You have won")
WaitDialog()
Unpause()
Quit(true)
end

if GetEmpire(1):GetNumOwnedAsteroids() == 0 then
Pause()
MessageBox("You have lost")
WaitDialog()
Unpause()
Quit(false)
end


Just replace "99999" with however many asteroids are in your level.  :>

Loops like this aren't always a suitable way of setting up the win/lose condition, let me know if this method isn't going to work for the level you're making.

I tried this and it didn't work. so far i have 12 asteroids, including my own, so i typed in 12 where it said, but no luck so far.

---

Q2-
the other question is more aesthetic. ive played around with the background colour and it immediately got me thinking, is it possible to create a constantly unduataing/ pulsating loop or cycle of colours?

reply -
The command to change the background is:

SetBackdropColour(red,green,blue)

So for the red green and blue values, if youhave SetBackdropColour(255,255,255) that's white.  (0,0,0) is black.  (255,0,0) is red, and so on.

You can use variables too.  Check this out:

Code:

while GameRunning() do

rcolour = GetAsteroid(0):GetNumSeedlings(1)

if rcolour > 255 then
rcolour = 255
end

SetBackdropColour(rcolour,0,0)
coroutine.yield()
end

That code will continually check how many seedlings the player has on Asteroid ID 0, and vary the amount of red in the background accordingly.  I also put a small If statement in there, to make sure we never try to set a value of 300 or something like that - the values for the backdrop colour are only supposed to go up to 255.

So what if you want to create cyclical patterns, like in Day & Night?
One way to do it is to use mathmatical functions to create a variable that goes up and down based on the Game Time.
Here's an example of how you can do this;

Code:

while GameRunning() do

-- first we record the time
time = GetGameTime()

-- we can divide the time by a number - or multiply it - to slow down or speed up the pulses.
time = time / 3

-- now to get the pulsing effect:
x = math.sin(time)

-- x is now a value that ranges up and down between -1 and 1 over time.


-- for this example we want a value that ranges between 0 and 1.
-- so lets modify x a bit.

x = x + 1
-- now x ranges between 0 and 2
x = x / 2
-- now it ranges between 0 and 1

x = x * 255
-- now it ranges between 0 and 255

SetBackdropColour(0,0,x)
-- this will make the background pulse between black and blue.  :>

coroutine.yield()
end


Hopefully this makes things clearer :>

---

So, those were my first Q's.
I've yet to try the colour cycle but will be doing so today and will post my results up here.

In addition...

The player is always empire 1.  :>
Empire 0 is the greys, or "unclaimed" asteroids.  If you don't explicitly set an asteroid to belong to another empire it will default to belonging to Empire 0.

GetEmpire is an example of a "function".  the GetEmpire() function needs a number or variable in the brackets, or it won't work.  Functions either need some variables passed to them, or do not.  In this case we DO need to give it a number because the function needs to know which Empire we are referring to.

GetNumOwnedAsteroids() doesn't need a variable passed to it - it's a function you run on an AI or empire and it simply returns how many asteroids that empire owns.

---

Thanks to Annikk. for your help and support. and inspiration to give this thing a try.
:)

AWS

AWS

  • Achiever
  • Arboreal Being
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 274
Re: Level design/ Code questions from a beginner
« Reply #1 on: April 04, 2010, 02:34:59 PM »
one thing ive noticed is that whenever i get an error message when trying to load the level im working on, is the dialog box telling me 'cant load level' obscures the error message box behind it, that gives me the info as to what is causing the error. i have to peer right up to the screen to try and work out what the text says and for the most part, i can never work out what it says!

anyone else have this issue with the 2 dialog boxes on top of each other?


AWS

  • Achiever
  • Arboreal Being
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 274
Re: Level design/ Code questions from a beginner
« Reply #2 on: April 04, 2010, 03:55:41 PM »
3 things -

1- what does the 'r' refer to in 'rcolour'. i see that in some of annikks code there is 'g' colour. what is the difference and why?

Code:

while GameRunning() do

rcolour = GetAsteroid(0):GetNumSeedlings(1)

if rcolour > 255 then
rcolour = 255
end

SetBackdropColour(rcolour,0,0)
coroutine.yield()
end


---
for the pulsing effect.

while GameRunning() do

-- first we record the time
time = GetGameTime()

-- we can divide the time by a number - or multiply it - to slow down or speed up the pulses.
time = time / 3

-- now to get the pulsing effect:
x = math.sin(time)

-- x is now a value that ranges up and down between -1 and 1 over time.


-- for this example we want a value that ranges between 0 and 1.
lets modify x a bit.

x = x + 1
-- now x ranges between 0 and 2
x = x / 2
-- now it ranges between 0 and 1

x = x * 255
-- now it ranges between 0 and 255

SetBackdropColour(0,0,x)
-- this will make the background pulse between black and blue.  :>

coroutine.yield()
end[/color]

2- exactly why, or how, does the (0,0,x) part make it change between black and blue? i was hoping to have a range of say, 5 colours, that gradually, after every 45 seconds of game time, merge into the next colour, and so on. i would need to use the GameTime function for this.

---

3- to add asteroids ive merely been copying and pasting the previous code, so im ending up with lots of repititious code. i see that there is another way of doing this to avoid the ugliness and lengthiness of my approach. how do you add many asteroids, while still placing them where you want, without all the repetitive copy and pasting of the same code?

---

AWS

« Last Edit: April 04, 2010, 04:03:13 PM by AWS »

AWS

  • Achiever
  • Arboreal Being
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 274
Re: Level design/ Code questions from a beginner
« Reply #3 on: April 04, 2010, 06:48:34 PM »
more questions... :)


   t = 1600

   coordx = {}
   coordy = {}
   roidradius = {}

-What is the t = 1600 doing? is that just setting a particular letter and number value for later use? or is it specific to something?
-What are the coord and roidradius with those brackets doing?


      coordx = x
      coordy = y
   
   
      t = t + 294.5
      
      a.SendDistance = (roidradius * 7) + 1500

-What is this calculation?
Im looking for a way to set each asteroids' send distance to a percentage of the planet's size. ive got some small planets with absurdly huge distances while some big planets have almost no distance even though ive set them to what i think is right, it doesnt seem to be paying attention to it in game. hence this question.

-What is the AI Grace timer? i assume it's a minmum time before the enemy can attack you, is this correct? if so, are the values in seconds? eg.Globals.AI.GraceTimer=(120) or (9999)

AWS

annikk.exe

  • Achiever
  • Ent
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 1,794
Re: Level design/ Code questions from a beginner
« Reply #4 on: April 04, 2010, 07:35:24 PM »
Suggest to make a cup of tea before reading this.  It will take a while, as I have answered each question In Full :>



Quote
Code: [Select]
while GameRunning() do

rcolour = GetAsteroid(0):GetNumSeedlings(1)

if rcolour > 255 then
rcolour = 255
end

SetBackdropColour(rcolour,0,0)
coroutine.yield()
end

1- what does the 'r' refer to in 'rcolour'. i see that in some of annikks code there is 'g' colour. what is the difference and why?

rcolour is just a variable i created in order to have something by which to refer to the amount of Red in the background colour.
You can see where I create it initially:

rcolour = GetAsteroid(0):GetNumSeedlings(1)

...and then where I use it later - instead of a fixed number - to set the amount of Red in the background colour:

SetBackdropColour(rcolour,0,0)


So you see, you can create a variable with a name of your choosing simply by "declaring" what it's value is.
In this example we created a variable called rcolour when we wrote that it should be equal to the number of Seedlings belonging to player 1 on Asteroid ID 0.

The reason I chose to call it "rcolour" is because it's a nice shorthand way of writing "the amount of red".  I could just as easily have called it "redamount", or simply "red", and it would work fine.


Another important thing to understand is that All Variables Equal Nil Until You Declare Otherwise.
Nil is not the same thing as 0.
Nil means "no value".

This can be useful, for example if you want to check if something has happened.  If say, the player moves a certain number of seedlings to an asteroid, you can create a trap for this with a "if, then, else" command, and the result will be to declare a variable like this: Fluffy = 0.
Then later on you can check If Fluffy == Nil and if that is true, then you will be able to say that the player hasn't moved that number of seedlings to the asteroid yet.  But if the value of Fluffy was not nil, but 0, then we know that the player HAS moved that number of seedlings to the target asteroid.

For practical purposes it's often useful to invert it, and say if the value of Fluffy is NOT equal to Nil, then do something... else do nothing.  You do that by using ~= instead of ==.
So:
== Is Equal To
~= Is NOT Equal To



Oh and by the way, gcolour as you may have guessed by now was simply the variable I created in order to control the amount of Green in the background colour.  :>
So it would have been like this:

SetBackdropColour(rcolour,gcolour,bcolour)








Quote
2- exactly why, or how, does the (0,0,x) part make it change between black and blue? i was hoping to have a range of say, 5 colours, that gradually, after every 45 seconds of game time, merge into the next colour, and so on. i would need to use the GameTime function for this.

(0,0,x) is key for the following reason: the 0,0 is fixed, but x is a variable.  That means its value can change during the course of play.  As opposed to the 0,0 which are fixed and will stay the same through the whole game.

To understand the whole, you have to understand each of the parts.

When the game loads, it runs all of the commands in function LevelSetup().  Then the game begins, the player may start to give orders to their seedlings etc, and the function LevelLogic() part of the level kicks in.

The While GameRunning() do command is used right at the start of the function LevelLogic() section.
The end of the While GameRunning() do section is signified by:

coroutine.yield()
end


This command basically says "While the game is running, continually run the commands in this section".


So take a moment to imagine this: The game is continously running these commands, and depending on the number of commands it has to run it may do so several hundred or thousand times a second.

Now we start to imagine the commands we are putting into this section in a different way - it is as if they are tiny slices of time.

Each "game cycle", as I like to refer to them as, we declare that the variable time is equal to the Game Time.
So imagine as the game constantly refreshes the value of the time, each cycle increasing it by a tiny tiny fraction of a millisecond.

Now we have a variable that we can plug into a function.  :>

Immedietely, we could do this:

SetBackdropColour(time,time,time)

So that would mean when the game starts, it sets the value of time and it's basically 0 because the Game Time on the very first game cycle will be pretty much 0.  So it would then set the backdrop command to near enough (0,0,0) which is Black.  It would set the backdrop to (0,0,0) because the value of time is 0 and we are setting it as (time,time,time) in the command we used.


But then, as the game goes on, say after one minute (ie 60 seconds), the value of time is constantly refreshed and is now way up at 60.  That means we'll be getting a backdrop(60,60,60) which is dark grey!  You will actually be able to see the background colour becoming gradually whiter and whiter as the game time goes up, and the value of the time variable goes up.

After about 4 minutes the background will be completely white... and once the game time is over 255 seconds the behaviour may be unpredictable :P



Now we have a variable called time that increases as time goes by.
This is useful for lots of things, but there are some circumstances where we want a variable that goes up and down as time goes by... rather than just increasing forever.

To make a variable that does this, we need to use some clever maths.  That's where the math.sin function comes in.

Hmm.  I have realised just now that I picked a bit of an unfortunate variable name "x".  Lets pretend it was actually called "bcolour" - that will be less confusing...

So the complete function LevelLogic() code would be like this:

Code: [Select]
function LevelLogic()
  while GameRunning() do

    -- first we record the time
    time = GetGameTime()

    -- we can divide the time by a number - or multiply it - to slow down or speed up the pulses.
    time = time / 3

    -- now to get the pulsing effect:
    bcolour = math.sin(time)

    -- bcolour is now a value that ranges up and down between -1 and 1 over time.


    -- for this example we want a value that ranges between 0 and 1.
    -- lets modify bcolour a bit.

    bcolour = bcolour + 1
    -- now bcolour ranges between 0 and 2

    bcolour = bcolour / 2
    -- now it ranges between 0 and 1

    bcolour = bcolour * 255
    -- now it ranges between 0 and 255

    SetBackdropColour(0,0,bcolour)
    -- this will make the background pulse between black and blue.  :>

    coroutine.yield()
  end
end





Do you remember in maths class drawing graphs of Y = Sin(X) ?  Perhaps not, but if you plot this equation on a graph then this is what it will look like:






It's a wavy line.  It pulses as a perfect spectral wave, free from spikes and jitters!  Beautiful to crazy mathematician types, and very useful for creating pulsing effects in levels.

So how do we use this crazy beast?  Well, like all mathematical formulas, you basically just plug in the numbers you want and away you go.



Y = Sin(X)

..becomes..

bcolour = Sin(time)



So now we are basically saying that the up and down motion on that graph is equal to bcolour.  The X-Axis on the graph is time, or in our case literally our variable called time.

So what you _actually_ get for bcolour from that command, is a value that goes between 1 and -1.  The very top of the curve on the graph is 1, and the very bottom is -1, with 0 being the horizontal axis.  Try to look at the graph and visualise this - horizontal is time, vertical is resulting value of bcolour.  You need to understand this in order to understand how the pulsing effect works.


Then we just do a bit more arithmetic on the variable to modify the number to be more useful, and we are able to create a variable with a value that ranges between 0 and 255.  :>

Then, finally, we simply plug that variable into the command like so:

SetBackdropColour(0,0,bcolour)

And voila, at the bottom of the curve (bcolour = 0) we will get (0,0,0) which is black, and at the top of the curve (bcolour = 255) we will get (0,0,255) which is blue.  :>






Quote
3- to add asteroids ive merely been copying and pasting the previous code, so im ending up with lots of repititious code. i see that there is another way of doing this to avoid the ugliness and lengthiness of my approach. how do you add many asteroids, while still placing them where you want, without all the repetitive copy and pasting of the same code?

You can add asteroids in lots of different ways.
You can place them one by one by writing out their positions and attributes individually.
Or you can use the inbuilt AddAsteroidRing(number of Asteroids, X-coordinate of the center, Y-coordinate of the centre, overall radius of the ring, width of the ring)

The way I did it in Day & Night, and also for Infected Empire, is to use a for loop.
That basically says, "for this number of times, run these commands" - similar to the "While" loop we talked about earlier, but it also lets you use "this" as a variable.  So you can count which pass you are on.
So in Day & Night the For loop looked like this:

for i=1,21 do

So I'm saying, "run all of the below commands, and each time you run them, increment "i" by one, until you reach 21, then stop".
The "1" refers to the number to start counting FROM.  Sometimes its more useful to start counting 0,1,2,3,4,5,6... instead of 1,2,3,4,5,6...


This leads perfectly onto the next question....



Quote
4- What is the t = 1600 doing? is that just setting a particular letter and number value for later use? or is it specific to something?

...then, for the commands nestled inside my For loop, I plugged in the mathematical formula for a spiral, and used the "t" value as the "period", or the amount to go further round the spiral before plopping the next asteroid down.

So I made my asteroids coordinates with this spiral command:

x = math.cos(t) * t
y = math.sin(t) * t


and then each time it runs through the For loop, it also does this:

t = t + 275

t is the amount further round the spiral we shall travel, before we lay another an asteroid thusly:

a = AddAsteroidWithAttribs(x,y,s,e,sp)

x and y for each asteroid are thus calculated based on the period t which is incremented on every pass of the For loop, i.


To be honest this was quite advanced - maybe it would be better to make some basic maps first before you start worrying about procedural generation :P





Will start a new post to answer the rest.
« Last Edit: April 05, 2010, 11:02:50 AM by annikk.exe »

AWS

  • Achiever
  • Arboreal Being
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 274
Re: Level design/ Code questions from a beginner
« Reply #5 on: April 04, 2010, 08:06:39 PM »
 :-\ sorry!

i have another question.

ive been trying to get this win condition you suggested, annikk, to work. so far ive tried two versions.
one results in an instant 'you have lost' message, the other, the one below, results in an instant 'you have won' message! seems weird, imo! the error that it displays is
'Attempt to yield across metamethod/ C-call boundary', in both cases.

the code causing the instant win dialog box is;

while GameRunning() do

   if GetEmpire(2):GetNumOwnedAsteroids() == 0 then
      
   Pause()
   MessageBox("you have won.")
   WaitDialog()
   Unpause()
   Quit(true)
   end

   if GetEmpire(1):GetNumOwnedAsteroids() == 0 then
   Pause()
   MessageBox("You have lost")
   WaitDialog()
   Unpause()
   Quit(false)
   end

coroutine.yield()
end


So - in light of this, in order to make my eventual finished map more interesting, i wanted about 2 or 3 different enemies. this will no doubt have an impact on the coding of the win condition.
erm... any help with that one?

 :-[

annikk.exe

  • Achiever
  • Ent
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 1,794
Re: Level design/ Code questions from a beginner
« Reply #6 on: April 04, 2010, 08:22:05 PM »
I'm still working on the other questions but the most likely reason for an instant win is that the terms of the If statement are being met.

Does Empire 2 own any asteroids during the first millisecond of the game?

If you post the entire level code in "[ code]" tags I'll check it for you :>

AWS

  • Achiever
  • Arboreal Being
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 274
Re: Level design/ Code questions from a beginner
« Reply #7 on: April 04, 2010, 08:33:22 PM »
this is the whole thing so far. it feels kinda naked, revealing ALL the code, but it's certainly nothing special. some of the globals are pulled directly from one of your maps without me really knowing what it means!  ::)
asteroids 4 and 10 have 0 as the owner, all the rest have 2. id like to add 1 or 2 more enemy races before its finished. but all the roids are inhabited on game start.

Code: [Select]
function LevelSetup()

-- Set Global Values
Globals.G.Asteroids=(0)
Globals.G.EnemyFactionsMin=(1)
Globals.G.EnemyFactionsMax=(1)
Globals.Asteroids.SpawnCap=100
Globals.Asteroids.SeedlingCap=5000
Globals.Asteroids.MinSendDistance=0.5
Globals.Asteroids.MaxSendDistance=0.5
Globals.AI.GraceTimer=(120)

SetBackdropColour (101,250,155)


-- Asteroid 0 - my starting asteroid
a = AddAsteroidWithAttribs(0,0, 0.8,0.6,0.7)
a.Owner = 1
a.TreeCap = 5
a:SetRadius(550)
a.SendDistance = 2100

a:AddSeedlings(77)
a.Moveable = False


-- Asteroid 1 - winning asteroid --1st Giant Planet
b = AddAsteroidWithAttribs(7000,1500, 0.6,0.8,0.2)
b.Owner = 2
b.TreeCap = 7
b:SetRadius(995)
b.SendDistance = 1500
s = b:AddDysonTree()
s:LevelUp()
s:LevelUp()
s:LevelUp()
b:AddSeedlings(39)
b.Moveable = False


-- Asteroid 2
b = AddAsteroidWithAttribs(1500,1900, 0.2,0.3,0.1)
b.Owner = 2
b.TreeCap = 3
b:SetRadius(450)
b.SendDistance = 650

b:AddSeedlings(20)
b.Moveable = False

-- Asteroid 3
b = AddAsteroidWithAttribs(-1600,-850, 0.1,0.5,0.8)
b.Owner = 2
b.TreeCap = 3
b:SetRadius(250)
b.SendDistance = 250

b:AddSeedlings(10)
b.Moveable = False

-- Asteroid 4
b = AddAsteroidWithAttribs(-1700,2100, 0.5,0.5,0.1)
b.Owner = 0
b.TreeCap = 3
b:SetRadius(450)
b.SendDistance = 600

b:AddSeedlings(25)
b.Moveable = False

-- Asteroid 5
b = AddAsteroidWithAttribs(2500,800, 0.1,0.4,0.6)
b.Owner = 2
b.TreeCap = 2
b:SetRadius(150)
b.SendDistance = 100

b:AddSeedlings(18)
b.Moveable = False

-- Asteroid 6
b = AddAsteroidWithAttribs(3200,2200, 0.1,0.3,0.5)
b.Owner = 2
b.TreeCap = 4
b:SetRadius(400)
b.SendDistance = 500

b:AddSeedlings(11)
b.Moveable = False

-- Asteroid 7
b = AddAsteroidWithAttribs(2000,-2900, 0.2,0.3,0.5)
b.Owner = 2
b.TreeCap = 3
b:SetRadius(200)
b.SendDistance = 7000

b:AddSeedlings(4)
b.Moveable = False

-- Asteroid 8
b = AddAsteroidWithAttribs(1900,-900, 0.4,0.2,0.5)
b.Owner = 2
b.TreeCap = 4
b:SetRadius(420)
b.SendDistance = 600

b:AddSeedlings(0)
b.Moveable = False

-- Asteroid 9
b = AddAsteroidWithAttribs(2900,-2100, 0.4,0.3,0.5)
b.Owner = 2
b.TreeCap = 4
b:SetRadius(350)
b.SendDistance = 1000


-- Asteroid 10
b = AddAsteroidWithAttribs(-2900,-1900, 0.4,0.4,0.6)
b.Owner = 0
b.TreeCap = 3
b:SetRadius(200)
b.SendDistance = 700

b:AddSeedlings(0)
b.Moveable = False

-- Asteroid 11
b = AddAsteroidWithAttribs(-1800,-2600, 0.4,0.3,0.4)
b.Owner = 2
b.TreeCap = 4
b:SetRadius(320)
b.SendDistance = 700

b:AddSeedlings(15)
b.Moveable = False

-- Asteroid 12
b = AddAsteroidWithAttribs(100,-3100, 0.4,0.5,0.4)
b.Owner = 2
b.TreeCap = 2
b:SetRadius(210)
b.SendDistance = 200

b:AddSeedlings(11)
b.Moveable = False

-- Asteroid 13
b = AddAsteroidWithAttribs(-3300,-1200, 0.4,0.3,0.4)
b.Owner = 0
b.TreeCap = 4
b:SetRadius(320)
b.SendDistance = 600

b:AddSeedlings(15)
b.Moveable = False

-- Asteroid 14
b = AddAsteroidWithAttribs(800,3100, 0.4,0.5,0.4)
b.Owner = 2
b.TreeCap = 2
b:SetRadius(210)
b.SendDistance = 500

b:AddSeedlings(11)
b.Moveable = False

-- Asteroid 15 -- 2nd Giant planet
b = AddAsteroidWithAttribs(-5500,-4500, 0.8,0.7,0.8)
b.Owner = 2
b.TreeCap = 7
b:SetRadius(995)
b.SendDistance = 1500
s = b:AddDysonTree()
s:LevelUp()
s:LevelUp()
b:AddSeedlings(7)
b.Moveable = False

-- Asteroid 16
b = AddAsteroidWithAttribs(-2800,2400, 0.4,0.5,0.4)
b.Owner = 2
b.TreeCap = 2
b:SetRadius(210)
b.SendDistance = 500

b:AddSeedlings(11)
b.Moveable = False

end


function LevelLogic()


-- Greeting
Timer = GetGameTime() + 3


while GetGameTime() < Timer do

coroutine.yield()
end

Pause()
MessageBox("Greetings... ")
WaitDialog()
Unpause()


end


-- Victory Trigger

while GameRunning() do

if GetEmpire(2):GetNumOwnedAsteroids() == 0 then

Pause()
MessageBox("you have won.")
WaitDialog()
Unpause()
Quit(true)
end

if GetEmpire(1):GetNumOwnedAsteroids() == 0 then
Pause()
MessageBox("You have lost")
WaitDialog()
Unpause()
Quit(false)
end

coroutine.yield()
end

annikk.exe

  • Achiever
  • Ent
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 1,794
Re: Level design/ Code questions from a beginner
« Reply #8 on: April 04, 2010, 08:56:27 PM »
Ok the reason why that doesn't work properly is that your winning/losing code is outside of the function LevelLogic().  It is outside it because it appears AFTER the "end" that closes off the function LevelLogic().

Here's a fixed version.  :>


Code: [Select]
function LevelSetup()

-- Set Global Values
Globals.G.Asteroids=(0)
Globals.G.EnemyFactionsMin=(1)
Globals.G.EnemyFactionsMax=(1)
Globals.Asteroids.SpawnCap=100
Globals.Asteroids.SeedlingCap=5000
Globals.Asteroids.MinSendDistance=0.5
Globals.Asteroids.MaxSendDistance=0.5
Globals.AI.GraceTimer=(120)

SetBackdropColour (101,250,155)


-- Asteroid 0 - my starting asteroid
a = AddAsteroidWithAttribs(0,0, 0.8,0.6,0.7)
a.Owner = 1
a.TreeCap = 5
a:SetRadius(550)
a.SendDistance = 2100

a:AddSeedlings(77)
a.Moveable = False


-- Asteroid 1 - winning asteroid --1st Giant Planet
b = AddAsteroidWithAttribs(7000,1500, 0.6,0.8,0.2)
b.Owner = 2
b.TreeCap = 7
b:SetRadius(995)
b.SendDistance = 1500
s = b:AddDysonTree()
s:LevelUp()
s:LevelUp()
s:LevelUp()
b:AddSeedlings(39)
b.Moveable = False


-- Asteroid 2
b = AddAsteroidWithAttribs(1500,1900, 0.2,0.3,0.1)
b.Owner = 2
b.TreeCap = 3
b:SetRadius(450)
b.SendDistance = 650

b:AddSeedlings(20)
b.Moveable = False

-- Asteroid 3
b = AddAsteroidWithAttribs(-1600,-850, 0.1,0.5,0.8)
b.Owner = 2
b.TreeCap = 3
b:SetRadius(250)
b.SendDistance = 250

b:AddSeedlings(10)
b.Moveable = False

-- Asteroid 4
b = AddAsteroidWithAttribs(-1700,2100, 0.5,0.5,0.1)
b.Owner = 0
b.TreeCap = 3
b:SetRadius(450)
b.SendDistance = 600

b:AddSeedlings(25)
b.Moveable = False

-- Asteroid 5
b = AddAsteroidWithAttribs(2500,800, 0.1,0.4,0.6)
b.Owner = 2
b.TreeCap = 2
b:SetRadius(150)
b.SendDistance = 100

b:AddSeedlings(18)
b.Moveable = False

-- Asteroid 6
b = AddAsteroidWithAttribs(3200,2200, 0.1,0.3,0.5)
b.Owner = 2
b.TreeCap = 4
b:SetRadius(400)
b.SendDistance = 500

b:AddSeedlings(11)
b.Moveable = False

-- Asteroid 7
b = AddAsteroidWithAttribs(2000,-2900, 0.2,0.3,0.5)
b.Owner = 2
b.TreeCap = 3
b:SetRadius(200)
b.SendDistance = 7000

b:AddSeedlings(4)
b.Moveable = False

-- Asteroid 8
b = AddAsteroidWithAttribs(1900,-900, 0.4,0.2,0.5)
b.Owner = 2
b.TreeCap = 4
b:SetRadius(420)
b.SendDistance = 600

b:AddSeedlings(0)
b.Moveable = False

-- Asteroid 9
b = AddAsteroidWithAttribs(2900,-2100, 0.4,0.3,0.5)
b.Owner = 2
b.TreeCap = 4
b:SetRadius(350)
b.SendDistance = 1000


-- Asteroid 10
b = AddAsteroidWithAttribs(-2900,-1900, 0.4,0.4,0.6)
b.Owner = 0
b.TreeCap = 3
b:SetRadius(200)
b.SendDistance = 700

b:AddSeedlings(0)
b.Moveable = False

-- Asteroid 11
b = AddAsteroidWithAttribs(-1800,-2600, 0.4,0.3,0.4)
b.Owner = 2
b.TreeCap = 4
b:SetRadius(320)
b.SendDistance = 700

b:AddSeedlings(15)
b.Moveable = False

-- Asteroid 12
b = AddAsteroidWithAttribs(100,-3100, 0.4,0.5,0.4)
b.Owner = 2
b.TreeCap = 2
b:SetRadius(210)
b.SendDistance = 200

b:AddSeedlings(11)
b.Moveable = False

-- Asteroid 13
b = AddAsteroidWithAttribs(-3300,-1200, 0.4,0.3,0.4)
b.Owner = 0
b.TreeCap = 4
b:SetRadius(320)
b.SendDistance = 600

b:AddSeedlings(15)
b.Moveable = False

-- Asteroid 14
b = AddAsteroidWithAttribs(800,3100, 0.4,0.5,0.4)
b.Owner = 2
b.TreeCap = 2
b:SetRadius(210)
b.SendDistance = 500

b:AddSeedlings(11)
b.Moveable = False

-- Asteroid 15 -- 2nd Giant planet
b = AddAsteroidWithAttribs(-5500,-4500, 0.8,0.7,0.8)
b.Owner = 2
b.TreeCap = 7
b:SetRadius(995)
b.SendDistance = 1500
s = b:AddDysonTree()
s:LevelUp()
s:LevelUp()
b:AddSeedlings(7)
b.Moveable = False

-- Asteroid 16
b = AddAsteroidWithAttribs(-2800,2400, 0.4,0.5,0.4)
b.Owner = 2
b.TreeCap = 2
b:SetRadius(210)
b.SendDistance = 500

b:AddSeedlings(11)
b.Moveable = False

end


function LevelLogic()


-- Greeting
Timer = GetGameTime() + 3


while GetGameTime() < Timer do

coroutine.yield()
end

Pause()
MessageBox("Greetings... ")
WaitDialog()
Unpause()


-- Victory Trigger

while GameRunning() do

if GetEmpire(2):GetNumOwnedAsteroids() == 0 then

Pause()
MessageBox("you have won.")
WaitDialog()
Unpause()
Quit(true)
end

if GetEmpire(1):GetNumOwnedAsteroids() == 0 then
Pause()
MessageBox("You have lost")
WaitDialog()
Unpause()
Quit(false)
end

coroutine.yield()
end




end

annikk.exe

  • Achiever
  • Ent
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 1,794
Re: Level design/ Code questions from a beginner
« Reply #9 on: April 04, 2010, 09:16:11 PM »
Quote
Code: [Select]

   coordx = {}
   coordy = {}
   roidradius = {}


5- What are the coord and roidradius with those brackets doing?

That's me initialiasing a data structure called an Array.

An array is like a variable that has multiple different slots.

So for example, Fluffy[15] refers to a variable called Fluffy, with the value at slot number 15.



Here's a simple example of using arrays:

Code: [Select]
Fluffy = {}

for i = 1,5 do

Fluffy[i] = GetAsteroid(i):GetNumSeedlings(1)

end

That runs a For loop 5 times, and each time it makes the corresponding slot of Fluffy equal to the number of seedlings on Asteroid ID i.

So Fluffy[3] will be equal to the number of seedlings belonging to the player present on Asteroid ID 3.
So Fluffy[4] will be equal to the number of seedlings belonging to the player present on Asteroid ID 4.
and so on.

Arrays are useful for some more advanced stuff.




Quote
Code: [Select]
a.SendDistance = (roidradius * 7) + 1500
6- What is this calculation?  Im looking for a way to set each asteroids' send distance to a percentage of the planet's size. ive got some small planets with absurdly huge distances while some big planets have almost no distance even though ive set them to what i think is right, it doesnt seem to be paying attention to it in game. hence this question.

Earlier on in the code, I did some maths to calculate the radius of each asteroid based on its distance from the centre of the galaxy, and its energy, strength and speed.
The result of this maths is summarised in the variable roidradius which I then used to set the radius of each asteroid, like this:

a:SetRadius(roidradius)


I then decided I wanted to base the Send Distance of the asteroid off it's radius - seems pretty sensible.  So I did a.SendDistance = roidradius but of course that means that the Send Distance is tiny.  So I changed it to be a.SendDistance = roidradius * 10 and that was much more like it.
There was a problem though - very large asteroids had ridiculously huge send distances, and tiny asteroids had tiny send distances.
So to make it a bit more balanced in that regard, I changed it to a.SendDistance = (roidradius * 7) + 1500 and this means large asteroid send distances are not quite so huge, and tiny asteroids have a guaranteed minimum of 1500.  This seemed to work good.  :>



Quote
7- -What is the AI Grace timer? i assume it's a minmum time before the enemy can attack you, is this correct? if so, are the values in seconds? eg.Globals.AI.GraceTimer=(120) or (9999)

The Grace Timer is the amount of time until the default, inbuilt AI is allowed to start "using" an asteroid.
If you set a Global Grace Timer, the AI will be unable to do anything at all, until the timer is up.

If you set Globals.AI.GraceTimer=(99999) the AI will never get to use any asteroids and is effectively switched off.

You can also set grace timers on individual asteroids, this can be useful sometimes if you want some AI-owned asteroids to remain inactive until a certain point.
« Last Edit: April 05, 2010, 05:58:56 PM by annikk.exe »

AWS

  • Achiever
  • Arboreal Being
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 274
Re: Level design/ Code questions from a beginner
« Reply #10 on: April 04, 2010, 09:43:00 PM »
 :o
well, that was indeed very thorough. thank you very much.

i copied back your revised code and tried to load- guess what, no cigar!it wont load. with those 2 end's at the end, an error pops up saying '236: <eof> expected near 'end' ' -so i go to line 236, remove the end, and of course, i have no closing 'end' for the function section, and it wont load. bit a catch 22 there.

seems im a little stuck with this. of course, until i can sort this out i cant get on with fathoming that pulsating business. (to be honest, maths was not my strong point at school. far far from it...)

also, am i right in thinking that if i do a GetGlobalAsteroids with SendDistance, i can set up my own sum for setting the distance of all the asteroids without having to manually do each one?
something like,

a.SendDistance = GetGlobalAsteroidsRadius * 7 + 1500
to use your figures.

that doesnt look right to me after all, but i hope you can what im trying to do with it - im trying to say, find all the asteroids' radii, then set the send distance with the following sum.

---
i think ill have that tea now...
AWS

annikk.exe

  • Achiever
  • Ent
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 1,794
Re: Level design/ Code questions from a beginner
« Reply #11 on: April 04, 2010, 09:49:05 PM »
Proof-read the first reply and fixed lots of errors.  Try the updated code in it!  :>

I will test all of the code I put in here later tonight, and fix any bits that don't work.

njursten

  • Seedling
  • **
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 31
Re: Level design/ Code questions from a beginner
« Reply #12 on: April 04, 2010, 10:13:49 PM »
FYI, I'd keep the win/loss logic in the OnAsteroidTaken function. There's no point in rechecking the number of owned asteroids if there's hasn't been a change of ownership for an asteroid. If you want it to depend on the number of seedlings left you'd need to move it to the LevelLogic function though.

Too damn much text in here so I didn't read it all, but if annikk didn't tell you: To see the error message when a level fails to load, press the ~ key (left of 1 key). You'll see a list of all error messages since the game was started. You can enter commands here also, but it's not that useful. You can check variable values and stuff like that though.

annikk.exe

  • Achiever
  • Ent
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 1,794
Re: Level design/ Code questions from a beginner
« Reply #13 on: April 04, 2010, 10:21:56 PM »
Quote
   -- Asteroid 1 - winning asteroid --1st Giant Planet
   b = AddAsteroidWithAttribs(7000,1500, 0.6,0.8,0.2)

This will not work well.. the asteroid is placed too far away.  Try 6000,1500 maybe?

This was preventing the level from loading on my computer.

annikk.exe

  • Achiever
  • Ent
  • ****
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 1,794
Re: Level design/ Code questions from a beginner
« Reply #14 on: April 04, 2010, 10:38:59 PM »
Asteroid 8 was also preventing the level from loading for me.  I had to remove the command b.Moveable = true


Here it is, confirmed working:


Code: [Select]
function LevelSetup()

-- Set Global Values
Globals.G.Asteroids=(0)
Globals.G.EnemyFactionsMin=(1)
Globals.G.EnemyFactionsMax=(1)
Globals.Asteroids.SpawnCap=100
Globals.Asteroids.SeedlingCap=5000
Globals.Asteroids.MinSendDistance=0.5
Globals.Asteroids.MaxSendDistance=0.5
Globals.AI.GraceTimer=(120)

SetBackdropColour (101,250,155)


-- Asteroid 0 - my starting asteroid
a = AddAsteroidWithAttribs(0,0, 0.8,0.6,0.7)
a.Owner = 1
a.TreeCap = 5
a:SetRadius(550)
a.SendDistance = 2100

a:AddSeedlings(77)
a.Moveable = False


-- Asteroid 1 - winning asteroid 1st Giant Planet
b = AddAsteroidWithAttribs(6000,1500, 0.6,0.8,0.2)
b.Owner = 2
b.TreeCap = 7
b:SetRadius(995)
b.SendDistance = 1500
s = b:AddDysonTree()
s:LevelUp()
s:LevelUp()
s:LevelUp()
b:AddSeedlings(39)
b.Moveable = False


-- Asteroid 2
b = AddAsteroidWithAttribs(1500,1900, 0.2,0.3,0.1)
b.Owner = 2
b.TreeCap = 3
b:SetRadius(450)
b.SendDistance = 650

b:AddSeedlings(20)
b.Moveable = False


-- Asteroid 3
b = AddAsteroidWithAttribs(-1600,-850, 0.1,0.5,0.8)
b.Owner = 2
b.TreeCap = 3
b:SetRadius(250)
b.SendDistance = 250

b:AddSeedlings(10)
b.Moveable = False


-- Asteroid 4
b = AddAsteroidWithAttribs(-1700,2100, 0.5,0.5,0.1)
b.Owner = 0
b.TreeCap = 3
b:SetRadius(450)
b.SendDistance = 600

b:AddSeedlings(25)
b.Moveable = False


-- Asteroid 5
b = AddAsteroidWithAttribs(2500,800, 0.1,0.4,0.6)
b.Owner = 2
b.TreeCap = 2
b:SetRadius(150)
b.SendDistance = 100

b:AddSeedlings(18)
b.Moveable = False

-- Asteroid 6
b = AddAsteroidWithAttribs(3200,2200, 0.1,0.3,0.5)
b.Owner = 2
b.TreeCap = 4
b:SetRadius(400)
b.SendDistance = 500

b:AddSeedlings(11)
b.Moveable = False


-- Asteroid 7
b = AddAsteroidWithAttribs(2000,-2900, 0.2,0.3,0.5)
b.Owner = 2
b.TreeCap = 3
b:SetRadius(200)
b.SendDistance = 7000

b:AddSeedlings(4)
b.Moveable = False



-- Asteroid 8
b = AddAsteroidWithAttribs(1900,-900, 0.4,0.2,0.5)
b.Owner = 2
b.TreeCap = 4
b:SetRadius(420)
b.SendDistance = 600

b:AddSeedlings(0)



-- Asteroid 9
b = AddAsteroidWithAttribs(2900,-2100, 0.4,0.3,0.5)
b.Owner = 2
b.TreeCap = 4
b:SetRadius(350)
b.SendDistance = 1000


-- Asteroid 10
b = AddAsteroidWithAttribs(-2900,-1900, 0.4,0.4,0.6)
b.Owner = 0
b.TreeCap = 3
b:SetRadius(200)
b.SendDistance = 700

b:AddSeedlings(0)
b.Moveable = False

-- Asteroid 11
b = AddAsteroidWithAttribs(-1800,-2600, 0.4,0.3,0.4)
b.Owner = 2
b.TreeCap = 4
b:SetRadius(320)
b.SendDistance = 700

b:AddSeedlings(15)
b.Moveable = False

-- Asteroid 12
b = AddAsteroidWithAttribs(100,-3100, 0.4,0.5,0.4)
b.Owner = 2
b.TreeCap = 2
b:SetRadius(210)
b.SendDistance = 200

b:AddSeedlings(11)
b.Moveable = False

-- Asteroid 13
b = AddAsteroidWithAttribs(-3300,-1200, 0.4,0.3,0.4)
b.Owner = 0
b.TreeCap = 4
b:SetRadius(320)
b.SendDistance = 600

b:AddSeedlings(15)
b.Moveable = False

-- Asteroid 14
b = AddAsteroidWithAttribs(800,3100, 0.4,0.5,0.4)
b.Owner = 2
b.TreeCap = 2
b:SetRadius(210)
b.SendDistance = 500

b:AddSeedlings(11)
b.Moveable = False

-- Asteroid 15 -- 2nd Giant planet
b = AddAsteroidWithAttribs(-5500,-4500, 0.8,0.7,0.8)
b.Owner = 2
b.TreeCap = 7
b:SetRadius(995)
b.SendDistance = 1500
s = b:AddDysonTree()
s:LevelUp()
s:LevelUp()
b:AddSeedlings(7)
b.Moveable = False

-- Asteroid 16
b = AddAsteroidWithAttribs(-2800,2400, 0.4,0.5,0.4)
b.Owner = 2
b.TreeCap = 2
b:SetRadius(210)
b.SendDistance = 500

b:AddSeedlings(11)
b.Moveable = False



end


function LevelLogic()


-- Greeting
Timer = GetGameTime() + 3


while GetGameTime() < Timer do

coroutine.yield()
end

Pause()
MessageBox("Greetings... ")
WaitDialog()
Unpause()


-- Victory Trigger

while GameRunning() do

if GetEmpire(2):GetNumOwnedAsteroids() == 0 then

Pause()
MessageBox("you have won.")
WaitDialog()
Unpause()
Quit(true)
end

if GetEmpire(1):GetNumOwnedAsteroids() == 0 then
Pause()
MessageBox("You have lost")
WaitDialog()
Unpause()
Quit(false)
end

coroutine.yield()
end




end