I'm working on a Scorched Earth clone using xLIBC. Screenies so far (the square pixels are 'tanks'):






Note that this code is mostly untouched from the state it was in last night at 11:00 pm (I've been getting tired as early as 9 lately for some reason, so that was about the point where I started losing the ability to form coherent sentences), and as such it's preeeetty badly written. I'm working on optimizing it, but until that's done I've commented it so you guys can read it and hopefully (please?) help me out. Tank generation is the main thing that needs fixing; while I'm mostly happy with the results it produces, it takes 5-10 seconds on my CSE (depending on terrain) to generate positions, which is way too long for my liking-- I thought about calculating all values before the program starts, but that wouldn't work very well considering that terrain values (and thus, indirectly, tank positions) depend on user input at the beginning. So really, my only option here is to find a way to optimize it.

Anyway, enough rambling Very Happy Here's the code, fully commented:

Code:

DelVar SMenu("TERRAIN","rand",2,"Input ",3,"Slope",1,"Horizontal ish",4
Lbl 4:2->theta:Goto theta
Lbl 1
1->S //slope
randInt(7,35->theta //doesn't really matter what's stored to theta here
Goto theta
Lbl 2 //random terrain
randInt(30,100,80->L1 //80 because that's half the screen size (160)
Goto A
Lbl 3 //steepness of hills depends on user input or (theta)
Input theta
Lbl theta
abs(int(120/theta)-cumSum(randInt(~theta,theta,80->L1 // gives a list of values that are separated by anything from ~theta to theta, which can be used to create smooth hills.
//I forgot why int(120/theta) works, but it does (although if you enter a lower number like 5 it'll be a bit too high up on the screen, and if you enter 1 there won't really be any terrain)
Lbl A
If S //S flags whether or not terrain is a slope
SortD(L1 //this sorts the values from highest to lowest, which translates onscreen into a left-to-right upwards slope, like this: /
If S and randInt(0,1
SortA(L1 //ensures that it's not always upwards. Sometimes it'll be a l-r downwards slope, like this: \
real(0,1,1 //initiate drawing mode
real(8,3,200->A //color for terrain
real(7,9,0,0,160,120,255 //background, may change it to random color (or even an image?) at some point
real(8,2,0 //sets no offset, as I'm not planning to use screen-switching for the time being
randIntNoRep(0,79->L3 //has no use here but if I do it later, the delay is annoyingly noticeable. When done here it just seems like part of the map generation delay. It'll be used for tank placement a few lines down
For(B,0,79
L1(B+1
real(7,9,2B,Ans,2,Ans+(120-Ans),A //draws 2px wide rects
End
//start tank placement
L1-2->L1 //so that the tanks are a little bit above the terrain
Ans->L2
SortD(L2 //this gives the lowest-down values first, so valleys will be the first places to get tanks
1->N:{0
For(T,1,dim(L2
If dim(Ans)=sum(not(cumSum(5>abs(Ans-L2(T
//1+sum(not(cumSum(LIST=VAL gives the list index of a value of the list. For instance 1+sum(not(cumSum(7={3,1,7 returns 3. I've omitted the '1+' here to save space.
//I didn't actually explain why it's used here-- before this loop, L2 contains lots of repeated values. This loop removes all the repeats.
augment(Ans,{L2(T
End
cumSum(DeltaList(Ans->L2 //removes the first element (the 0)
dim(Ans)-5->Y //Ensures that there won't ever be more than 5 (6?) tanks
For(B,1,80 //tank drawing loop
If max(L2=L1(1+L3(B:Then //This is where L3 is used. If I just iterated through everything normally (1-80) then the tanks would be concentrated on the left side of the screen; this adds some randomness to it.
real(7,3,2L3(B),L1(1+L3(B)),A+25,3,0 //just a pixel for now, nothing fancy
sum(not(cumSum(L2=L1(1+L3(B //putting this on its own line saves five bytes (again, finding list index)
seq(L2(X+(X>Ans)),X,1,dim(L2)-1->L2 //removes the value at Ans
dim(Ans //again, on its own line to save space
If Ans<Y or Ans=1:81->B //ends the For loop if there can't be any more tanks
End
End
Pause

edits: clarified code some more | added screenies |
Some updates--

-I originally had it only calculate up to 80 (and draw 2px rectangles) to save speed; however, I've found that it's actually not that much slower to calculate all the way to the full screen width, being 160. The only thing it wastes is RAM, which hopefully shouldn't be too much of an issue as I'll delete the offending lists once map drawing/tank placement is done. Later today I'll update the OP with the new code.

-Tank placement is still too slow, and needs to be either fixed or scrapped entirely. I haven't looked at how Scarth does it yet, but it looks like it just picks a random place on the map- which I was trying to avoid because sometimes the map goes offscreen (so if a tank lands on an offscreen part it'll be impossible for it to move; my current code's purpose is to find the lowest points on the map for the tanks to be), but it looks like I'll have to do it anyway. Scarth also finds a way to stop the map from going offscreen, so I'll take a look at that.
M. I. Wright wrote:
The only thing it wastes is RAM, which hopefully shouldn't be too much of an issue as I'll delete the offending lists once map drawing/tank placement is done. Later today I'll update the OP with the new code.
Why do you need to store it at all? In Scarth, I use the fact that I can pixel-test the screen to determine where the ground is. GetPixelA and GetPixelB in xLIBC do the same thing.

Quote:
-Tank placement is still too slow, and needs to be either fixed or scrapped entirely. I haven't looked at how Scarth does it yet
Picks a random spot, then pxl-Test(s downwards until it finds the ground.

Quote:
Scarth also finds a way to stop the map from going offscreen, so I'll take a look at that.
One of the map invariants Scarth uses is that at least the bottom pixel of the screen must be colored at all times. Algorithmically-speaking, this is pretty easy. Scarth's terrain-rendering algorithm has three values: the Y position, the Y velocity, and the Y acceleration, which all do what they sound like. The acceleration is changed randomly based on which terrain type has been selected, and I believe the position, velocity, and acceleration are all truncated. That is, if the position is less than 164, it is repeatedly returned to 164 (and is capped on the lower end around 20 or 30, probably, to leave room for a tank on top). If the velocity is larger than Vmax or smaller than -Vmax, it is truncated to that value. I believe the acceleration is also truncated, and perhaps when the position is at the max or min Y value, it also resets the velocity and acceleration to 0.
KermMartian wrote:
M. I. Wright wrote:
The only thing it wastes is RAM, which hopefully shouldn't be too much of an issue as I'll delete the offending lists once map drawing/tank placement is done. Later today I'll update the OP with the new code.
Why do you need to store it at all? In Scarth, I use the fact that I can pixel-test the screen to determine where the ground is. GetPixelA and GetPixelB in xLIBC do the same thing.


I'm already using getPixel for tank gravity (it's very rudimentary so I'm not going to share anything just yet).
I actually thought that I'd explained why I iterate through the whole terrain list, but looking through the thread I guess I forgot to save that edit or something, so it's basically this bit of code from the OP:

Code:

SortD(L2 //this gives the lowest-down values (i.e. valleys) first, so tanks will be less likely to go offscreen
1->N:{0
For(T,1,dim(L2
If dim(Ans)=sum(not(cumSum(5>abs(Ans-L2(T //removes repeats so that tanks aren't right next to each other
//1+sum(not(cumSum(LIST=VAL gives the list index of a value of the list. For instance 1+sum(not(cumSum(7={3,1,7 returns 3, but if the value is not in a list it returns 1+dim(list). I've omitted the '1+' in the program to save space, as it's not necessary if you're not using it to reference a list element.
augment(Ans,{L2(T //only way I could find of doing it without using another list [as 1->Ans(1+dim(Ans doesn't work very well]
End

My reasoning for doing this is that sometimes the terrain generation [being cumSum(randInt(-X,X,160] goes off the top of the screen, so this code ensures that low-down areas get tanks first. I just realized, though (see last paragraph) that I could probably just scrap this altogether if I do the calculations inside the For() loop directly.

Quote:
Quote:
-Tank placement is still too slow, and needs to be either fixed or scrapped entirely. I haven't looked at how Scarth does it yet
Picks a random spot, then pxl-Test(s downwards until it finds the ground.

That's what I figured. See above for why I'm doing it differently.

Quote:
Quote:
Scarth also finds a way to stop the map from going offscreen, so I'll take a look at that.
One of the map invariants Scarth uses is that at least the bottom pixel of the screen must be colored at all times. Algorithmically-speaking, this is pretty easy. Scarth's terrain-rendering algorithm has three values: the Y position, the Y velocity, and the Y acceleration, which all do what they sound like. The acceleration is changed randomly based on which terrain type has been selected, and I believe the position, velocity, and acceleration are all truncated. That is, if the position is less than 164, it is repeatedly returned to 164 (and is capped on the lower end around 20 or 30, probably, to leave room for a tank on top). If the velocity is larger than Vmax or smaller than -Vmax, it is truncated to that value. I believe the acceleration is also truncated, and perhaps when the position is at the max or min Y value, it also resets the velocity and acceleration to 0.


Wow, that's way more complicated than mine! I just do cumSum(randInt(-X,X,160)) to generate terrain values, although this has the disadvantage of taking RAM and time to compute. If I end up deciding to get rid of the whole valley-finder-algorithm, which is very likely at this point, I'll be able to do these calculations directly inside the For() loop to both save space and allow bounds checking.

Edit: sister says that this is calculus/derivatives, which piqued my interest a lot-- if you don't mind, could you do a quick rundown on why/how it works and why it's a better option (if it is) than what I did? I'm nowhere near calculus in math yet.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement