Euflorium: The Eufloria Community
Eufloria => Eufloria Classic => Eufloria Classic Mods => Topic started by: Tomfloria on May 09, 2012, 02:11:43 AM
-
Right, i've had a little chat with Alex and he's helped me quite a bit, he gave me this code which I changed a bit because it wasn't a function.
This is at the start of levellogic
startTransition = true
p = 0
camX = GetCameraX()
camY = GetCameraY()
startX = camX
startY = camY
destX = 0
destY = -3000
while gamerunning() do
if startTransition then
p = p + 0.02
if (p > 1) then
p = 1
startTransition = false
end
camX = startX + (destX - startX) * p
camY = startY + (destY - startY) * p
SetCameraPosition(camX, camY)
end
coroutine.yield()
end
end
and then things get crazy... Whatdup. XD
-
I forgot to mention that the effect im going for is clean transitions from x,y to x,y, not just jumping from x,y to x,y
-
Hmm. I see what you are trying to do, and the code looks ok...
Lets work it out for some possible values.
startTransition = true
p = 0
camX = GetCameraX()
camY = GetCameraY()
startX = camX
startY = camY
destX = 0
destY = -3000
Lets use the following test values:
camX = 2000
camY = -3000
startX = 2000
startY = -3000
destX = 500
destY = 500
Then lets plug those into the code.
First we run this portion:
while gamerunning() do
if startTransition then
p = p + 0.02
if (p > 1) then
p = 1
startTransition = false
end
startTransition is true, so on the first run through of this code, p (currently 0) will become 0.02.
P is not more than 1, so the If conditional is not triggered, and startTransition remains true.
p = 0.02
startTransition = true
Next we come to this part:
camX = startX + (destX - startX) * p
camY = startY + (destY - startY) * p
SetCameraPosition(camX, camY)
end
Lets focus only on the camX variable.
Remeber, startX = 2000 and destX = 500.
camX = startX + (destX - startX) * p
becomes
camX = 2000 + (500 - 2000) * 0.02
camX = 2000 - 1500 * 0.02
Here there's a possible point where we could run into trouble... it's not clear whether the sum should be (2000 - 1500) * 0.02 = 10, or if it should be 2000 - (1500 * 0.02) = 1970.
10 and 1970 are dramatically different results. We want the X transition to start from 2000 and proceed toward 500. So 1970 sounds more like it than 10!
I think the crazyness you are seeing is a result of Lua naturally choosing the wrong mathemathetical route, as per above, and ending up with stupid values like 10.
I think the calculation you should be doing is:
camX = startX + ((destX - startX) * p)
camY = startY + ((destY - startY) * p)
If you change those two lines to be like I have them there, I bet you it works. :>
-
You could also make this even better by smoothing the transition with a math.sin(p)
How would you do that?
You'd need to make a modification to this code:
if (p > 1) then
p = 1
startTransition = false
end
and to this code:
camX = startX + ((destX - startX) * p)
camY = startY + ((destY - startY) * p)
But first lets focus on the conceptual stuff.
What is it we want to do? (in exacting detail..)
We want to move the camera from the current coordinates, to a new set of coordinates, with a smoothed motion. At the beginning of the transition, the camera moves slowly, accelerating. Halfway through the transition the camera has reached its maximum speed. At the end of the transition the camera is slowing down, until it smoothly comes to a stop at the very end.
How do we implement that?
We can obtain the smooth motion by using a sine or cosine.
Consider this graph:
(http://i.imgur.com/m87au.png)
The good old up and down wavy motion.
Ok, here's what we're gonna do; the X-axis on this graph shall represent p, which is linearly increasing at a rate of 0.02 every game cycle, with there being 60 game cycles per second.
The y-axis shall represent a proportion of how much distance we move per cycle.
So to get a smooth transition, we start by hardly moving at all, then halfway through we're moving quite fast, then right at the end we slow down again to 0.
So it looks like the sine wave will work best for this:
(http://i.imgur.com/hbOXK.png)
It will work best because it starts at 0 on the vertical axis (no movement), then increases rapidly (accelerating), reaching its maximum speed at x = (math.pi() / 2), then slowing down, until at x = (math.pi()) it comes to a stop.
It perfectly describes the motion that we want for our transitions. We just need to find a way to marry it to the amount of movement we want on any given transition.
In order to do that, we first need to know how many steps there will be in total. Since we're proceeding at a rate of 0.02, and we need to reach the value of pi (3.14159265...), it will take us 157 game cycles to reach pi according to my calculator.
It's going to be annoying to recalculate this stuff later on if you decide to change the speed of the transition to something other than 0.02, so lets nip this in the bud right now and start expressing that value this way:
startTransition = true
p = 0
speed = 0.02
steps = math.pi() / speed
camX = GetCameraX()
camY = GetCameraY()
startX = camX
startY = camY
destX = 0
destY = -3000
while gamerunning() do
if startTransition then
p = p + speed
if (p > math.pi()) then
p = math.pi()
startTransition = false
end
camX = startX + ((destX - startX) * p)
camY = startY + ((destY - startY) * p)
SetCameraPosition(camX, camY)
end
coroutine.yield()
end
end
During the transition we'll need to know how much to move by. We'll split it into vertical movement and horizontal movement.
First we'll need to know the total distance to move.
We get that with:
(destX - startX)
Then, we can divide that by the number of steps to get the average amount moved per step:
((destX - startX) / steps)
This gives us an amount which we can multiply together with math.sin (which is going to be a value starting at 0, increasing to 1, then going back down to 0).
So how will that work?
If the value was always 1, then we'd just have steps number of cycles, each time the movement would be ((destX - startX) / steps) amount of movement.
Instead we have a value that starts on 0, increases to 1, then decreases again to 0.
So, hmm... how to solve that problem?
I'm not sure of it, but I would hazard a guess that if you multiply that math.sin by 2, you're going to end up with values ranging between 0 and 2, and that the average amount of movement per step will be the same as if the value was a constant of 1.
In other words, I think if you multiply your sine by 2, you're going to end up with the correct amount of movement in total.
I might be wrong about that, but lets try and put together an implementation anyway. I'll leave you to troubleshoot it, if you wish.. :>
So we need to have:
(math.sin(p) * 2)
That should give us a value that ranges between 0 and 2 and 0 over the course of the transition.
Next we can put that together with the other stuff, to get this:
((destX - startX) / steps) * (math.sin(p) * 2)
That formula expresses how much we should move on each individual cycle, based on how far through the transition we are, what the start and destination coords are, and the number of steps (and thus the speed) in the transition.
So then we plug that into the code, and that gives us this:
startTransition = true
p = 0
speed = 0.02
steps = math.pi() / speed
camX = GetCameraX()
camY = GetCameraY()
startX = camX
startY = camY
destX = 0
destY = -3000
while gamerunning() do
if startTransition then
p = p + speed
if (p > math.pi()) then
p = math.pi()
startTransition = false
end
camX = startX + (((destX - startX) / steps) * (math.sin(p) * 2))
camY = startY + (((destY - startY) / steps) * (math.sin(p) * 2))
SetCameraPosition(camX, camY)
end
coroutine.yield()
end
end
Hope you've been able to follow this ok. Maybe you can see a little of my algorithm inventing process too...
I'd be interested to hear if it works. :>
Please post any corrections below guys, I'll edit when I have time. :>
-
Seems that you're talking about the Sine, not Cosine :)
Also, something I came up with just looking at your codes:
(It's just to show of an idea, it might not work!)
camX = startX + (destX - startX) * math.sin(GetCameraX()/destX*math.pi)
camY = startY + (destY - startY) * math.sin(GetCameraY()/destY*math.pi)
this should work immeadiatly when you allocate a new destination for X or Y, and it's give a smooth transition that Annikk was talking about. Though I don't know if the code works for the iOS version...
-
Seems that you're talking about the Sine, not Cosine :)
You're right :> I got the lines mixed up in the legend.
I'll edit. :>
-
Also, something I came up with just looking at your codes:
(It's just to show of an idea, it might not work!)
camX = startX + (destX - startX) * math.sin(GetCameraX()/destX*math.pi)
camY = startY + (destY - startY) * math.sin(GetCameraY()/destY*math.pi)
Don't think that would work because it doesn't take the number of steps into account.. we need to know the average step length so that we can multiply it with the math.sin to get the smoothing.
I'm not sure mine will work either though. Looking forward to hearing.. :> I've done quite a bit of editing now so it's reasonably well explained, I think...
-
Don't think that would work because it doesn't take the number of steps into account.. we need to know the average step length so that we can multiply it with the math.sin to get the smoothing.
I'm not sure mine will work either though. Looking forward to hearing.. :> I've done quite a bit of editing now so it's reasonably well explained, I think...
I guess this one will:
time = 30
camX = startX + (destX - startX) * math.sin(GetCameraX()/destX*math.pi) / time
camY = startY + (destY - startY) * math.sin(GetCameraY()/destY*math.pi) / time
I should automatically adjust and us as long time as it needs :)
I'll test it out actually, just for fun :)
-
You haven't defined Time...
-
See, here is where our strategies diverge, Aino. I sit and think about the problem for ages, and use lots of diagrams and exercises and work out small bits of the puzzle, before finally using the conceptual understanding I've gained to piece all the parts of the puzzle together.... whereas you just come straight out with an attempt at a formula. :>
-
Well Annikk: my subconsciousness do a lot of math apparently, because suddenly I have a formula in my head which I don't know the origin of except some inspiration from other sources :)
Edit: And FYI: the formula works, but fails at some points... Going back to trigonometry! haha :)
-
Get you're codes right boys :D and who's code is right, and what am I adding haha
-
Right nerds :p going to try it!
-
Here you go
-
Right Have a look at this guys, This is what I've done....
function LevelLogic()
StartLevelLogic()
--CameraTest() --MAKE SURE THERE IS -- BEFORE ACTUAL RELEASE YOU IDIOT...
startTransition = true
p = 0
camX = GetCameraX()
camY = GetCameraY()
startX = camX
startY = camY
destX = 0
destY = -3000
foundAsteroid1 = false
foundAsteroid2 = false
--In the game there are messages and what not, but i've deleted them for this purpose
WaitReal(4)
destX = 10000
destY = 10000
WaitReal(4)
destX = 20000
destY = 20000
while GameRunning() do
if startTransition then
p = p + 0.02
if (p > 1) then
p = 1
startTransition = false
end
camX = startX + ((destX - startX) * p)
camY = startY + ((destY - startY) * p)
end
CheckConditions()
coroutine.yield()
end
end
I can safely say, nothing works haha, This is using Annikks first post. Havn't tried the others but Sin and Cos don't work.
-
I've just read through your code Aino, and pasted it straight into my level 1 copying everything (I've made a backup) and it starts, I had to take the globals out though cause it's different for iPad, when loading it up nothing happens, but then I added a few SetCameraTarget(10000,10000) just to test, but nothing happens....
I also changed the
CameraStart = {x = 0, y = 0};
to
CameraStart = {x = 10000, y = 0};
And it starts up at 0,0 It's got to be an iPad Limitation.
-
function LevelSetup()
-- some random globals.. can't remember what I all need...
Globals.G.Asteroids=(0)
Globals.G.EnemyFactionsMin=(0)
Globals.G.EnemyFactionsMax=(0)
Globals.G.MinAsteroidSeparation=500
Globals.G.MaxAsteroidNeighbourDist=3500
Globals.G.StartingSeedlings=(10)
Globals.G.GreysProbability=0
-- add some asteroids... a start roid
a = AddAsteroidWithAttribs(0,0, 1,1,1)
a.Name = "Start"
a.Owner = 1
s = a:AddDysonTree()
-- and a destination roid... we need some roids so we can
-- have some kind of fixed, known frame of reference to
-- test the transition effect..
a = AddAsteroidWithAttribs(2000,-1000, 1,1,1)
a.Name = "Destination"
a.Owner = 1
s = a:AddDysonTree()
end
function LevelLogic()
-- initialise variables
startTransition = true
p = 0
camX = GetCameraX()
camY = GetCameraY()
startX = camX
startY = camY
destX = 2000
destY = -1000
-- begin shenanigans
while GameRunning() do
-- Hallo ! Is this the start? Are we transitioning ?
if startTransition then
-- if we are, start incrementing the counter...
p = p + 0.02
-- if we've reached the end of the transition..
if (p > 1) then
-- set p to a nice round 1, and flip the latch so the base conditional will no longer trigger.
p = 1
startTransition = false
end
-- time to set the camera distance.
-- camera position = start coordinate + ((destination coordinate - start coordinate) * the counter)
camX = startX + ((destX - startX) * p)
camY = startY + ((destY - startY) * p)
-- set the camera to the newly calculated coordinates
SetCameraPosition(camX, camY)
end
coroutine.yield()
end
end
Here is code for a complete working level with the screen transition thing.
Does this work for you?
-
Also, get the basic one working first before you dive into the math.sin stuff !
On that, I've since found out that my assumption that the average Y value of the sine line where 0 < X < math.pi() is not 0.5... it's actually about 0.67 or something, or more accurately, 2 / math.pi().
So that means my code for the smoothed transition is wrong. :> It will work kind of, but it will either overshoot the intended coordinates, or fall some way short.... I'm not quite sure which. In any case, I will see about fixing that at some point...
-
:O it works
-
The problem I found with the code I copied largely verbatim from your original post, was that you wrote:
while gamerunning() do
instead of
while GameRunning() do
It turned out it didn't even favour the incorrect bracket precendence in the maths, so this was the only problem all along.
Nice thread it spawned though.. :>
-
camX = startX + (((destX - startX) / steps) * (math.sin(p) / (2 / math.pi())))
camY = startY + (((destY - startY) / steps) * (math.sin(p) / (2 / math.pi())))
This... I think... maybe..
It needs the other supporting code too I guess.
I try it :>
-
Just check this though, I don't just want one camera position, I want one, then something, then another.
-- initialise variables
startTransition = true
p = 0
camX = GetCameraX()
camY = GetCameraY()
startX = camX
startY = camY
destX = 2000
destY = -1000
WaitReal(3)
destX = 0
destY = 0
the only thing I added to the whole file you added me was
WaitReal(3)
destX = 0
destY = 0
and thats stopped the transition working, even for the first one.
-
Heh, doesn't work.
Back to conceptual stuff I guess.
Anyways...
Just check this though, I don't just want one camera position, I want one, then something, then another.
-- initialise variables
startTransition = true
p = 0
camX = GetCameraX()
camY = GetCameraY()
startX = camX
startY = camY
destX = 2000
destY = -1000
WaitReal(3)
destX = 0
destY = 0
the only thing I added to the whole file you added me was
WaitReal(3)
destX = 0
destY = 0
and thats stopped the transition working, even for the first one.
Because you haven't defined a function called WaitReal(), perhaps?
-
Add this in at the very very bottom of the level file:
function WaitReal(number)
MessageBox(number)
end
Then it will work, because the WaitReal function has been defined. Not sure what you wanted it to do exactly, but currently it will produce a messagebox containing the number 3!
-
In the iOS version it's already defined in support.lua which defines many functions
-
Never heard of it :>
I'd recommend testing the gametime instead to find out if it's time to transition or not.
-
For example:
function LevelSetup()
-- some random globals.. can't remember what I all need...
Globals.G.Asteroids=(0)
Globals.G.EnemyFactionsMin=(0)
Globals.G.EnemyFactionsMax=(0)
Globals.G.MinAsteroidSeparation=500
Globals.G.MaxAsteroidNeighbourDist=3500
Globals.G.StartingSeedlings=(10)
Globals.G.GreysProbability=0
-- add some asteroids... a start roid
a = AddAsteroidWithAttribs(0,0, 1,1,1)
a.Name = "Start"
a.Owner = 1
s = a:AddDysonTree()
-- and a destination roid... we need some roids so we can
-- have some kind of fixed, known frame of reference to
-- test the transition effect..
a = AddAsteroidWithAttribs(2000,-1000, 1,1,1)
a.Name = "Destination"
a.Owner = 1
s = a:AddDysonTree()
end
function LevelLogic()
-- initialise variables
startTransition = true
p = 0
camX = GetCameraX()
camY = GetCameraY()
startX = camX
startY = camY
destX = 2000
destY = -1000
-- begin shenanigans
while GameRunning() do
-- Hallo ! Is this the start? Are we transitioning ?
if startTransition == true and GetGameTime() > 3 then
-- if we are, start incrementing the counter...
p = p + 0.02
-- if we've reached the end of the transition..
if (p > 1) then
-- set p to a nice round 1, and flip the latch so the base conditional will no longer trigger.
p = 1
startTransition = false
end
-- time to set the camera distance.
-- camera position = start coordinate + ((destination coordinate - start coordinate) * the counter)
camX = startX + ((destX - startX) * p)
camY = startY + ((destY - startY) * p)
-- set the camera to the newly calculated coordinates
SetCameraPosition(camX, camY)
end
coroutine.yield()
end
end
Again, fully working level.
The only change I needed to make was this line:
if startTransition then
I changed it to this:
if startTransition == true and GetGameTime() > 3 then
if startTransition and if startTransition == true are the same, I just prefer the latter because I think it's clearer. :>
-
WaitReal(1) would be wait 1 game time second
-
Well you've told me that the level doesn't work if you use the WaitReal command, so as above, my suggestion is to find a different way to implement the delay. :>
-
What I'm going to do, is focus on getting the levels done, and then when there done ill do the extra sexy bits like this, Thanks Annikk!
-
Probably a good plan. :> You'll get more comfortable with lua that way too.