Of targets, interface, and rotations...

BlitzPlus Forums/BlitzPlus Programming/Of targets, interface, and rotations...

Tomas Khan(Posted 2008) [#1]
I am planning a tower defense game -- except the "towers" are pretty detailed and are likely to be harder to turn (if they turn). Note that I haven't begun coding this particular program at all, but I have just discovered how to use ATan2, Sin, and Cos to aim a shot at something (which I credit to Saxon Physics and the lesson on vectors). Unfortunately, I don't understand some of the other things I think will be important to make the game work...

Question #1: How and where do you use First, Last, Before, and After? I tried to use First before in something -- I don't remember what, but I think it was something like this -- and it didn't work the way I thought it would. (These, I thought, would be useful in targeting, as towers often fire at the farthest-along enemy they can reach.) Key phrase "I thought." I probably won't use these, but the question brought up some new ones...

Question #2: For a human or animal sprite seen directly from above (as most of the "towers" I'm thinking of that require rotation will be) fitting into a 32 x 32 pixel box, how many rotations should make any possible angle look reasonable without making the whole lag drastically? I'm using CreateTimer() and WaitTimer() now, so the speed of the program depends less on the speed of the computer, but when I rotated something in real-time, it still slowed down a lot, and I suspect that having a different frame for every degree of rotation won't make the computer happy. Maneesh uses 16 as a middle ground between detail and speed, but that almost seems like just a few too few. Answered.

Question #3: In an interface that allows the user to click on an object to activate it (show its range and give it upgrades and all that), how do you go about making sure that one and only one is active?

I think that's all for now... but I expect I'll find more later, once I actually get around to getting all of the sprites done and then actually starting to code the thing. Oh well.

Anyway, if you know the answer to any of those, I would be very grateful if you could tell me. Thank you!


Matty(Posted 2008) [#2]
Q1 - First Last Before After are used with collections of types. I'll explain here:

(Can't guarantee syntax correct, not at a machine with blitz at present)
Type MyObject

Field X

End Type

For i=1 to 10
	MyInstance.MyObject = New MyObject
	MyInstance\X = i
Next

FirstInstance.MyObject = First MyObject
LastInstance.MyObject = Last MyObject
SecondInstance.MyObject = After FirstInstance
NinthInstance.MyObject = Before LastInstance

graphics 800,600,0,2
text 0,0,firstinstance\x
text 0,15,lastinstance\x
text 0,30,secondinstance\x
text 0,45,ninthinstance\x
flip
waitkey
delete each MyObject
end



Regarding using 'last' to target furthest - a bit unnecessary, I don't know your game's logic but the last instance of an 'enemy' is not necessarily the furthest away. Simply do a distance check through each of your enemies and pick the one with the highest value.

Question 2:

As many rotations as you want - just don't use the rotateimage command and expect it to perform well at real time. Pre render or prerotate your images as many times as you want, and then simply draw them. The PC doesn't care what your image looks like in blitzplus - it is just a collection of pixels after all - so will draw it just as fast if the little man is facing left as if he is facing right ---> as long as you have already stored the images in memory. DO NOT USE ROTATEIMAGE and expect realtime results....


Question 3:
Use a variable, and store whether that object is currently active.

For example:


Type IconObject

Field Name$
Field AmIActive

eND tYpe

Icon.IconObject=new IconObject
Icon\Name = "Switch 1"
Icon\AmIActive = 0

Icon.IconObject=new IconObject
Icon\Name = "Switch 2"
Icon\AmIActive = 0

;then somewhere later in your code you would do this:(pseudocode)

"CurrentIcon.IconObject is that of  Switch 1"
"if mouseclick on Switch 1 then 
DoNotAllowPress=0
For OtherIcons.IconObject=each IconObject
	If OtherIcons\AmIActive=1 and Handle(OtherIcons)<>Handle(CurrentIcon) then DoNotAllowPress=1:Exit 
next
If DoNotAllowPress=0 then
	do your standard action here for the new icon
endif 
endif 




gameproducer(Posted 2008) [#3]
#1 - Yeh, the last/first refer to where the object is stacked in memory... is it the "last one in the pile", or the "first one in the pile". It doesn't refer to 'closest' enemy.

For finding the closest enemy you could have something like this:
function getClosestEnemy.enemy(yourtower.tower)
   closest.enemy = null
   for e.enemy = each enemy
      if (closest.enemy = null)
         closest.enemy = e.enemy
      elseif (distance(yourtower, e.enemy) < (distance(yourtower, closest.enemy) 
         closest.enemy = e.enemy
      endif
   next
   return closest.enemy
end function 

Please notice that I used a non-existent "distance" function, but if you use 3d stuff, then of course you can use "entityDistance". If you use 2d stuff, then replace 'distance' with something that works.


Tomas Khan(Posted 2008) [#4]
#1 - Yeh, the last/first refer to where the object is stacked in memory... is it the "last one in the pile", or the "first one in the pile". It doesn't refer to 'closest' enemy.

Yes, but if you create the enemies in order of their coordinates and they're following a set path, I believe First would target the one at one end. Still, I've just realized that using First or Last could make the tower fire at something out of range, so figuring out the closest either to the tower or the end of the path (where they go out and make you lose lives) is definitely a better way.

Regarding the rotations -- I think I'll just use 16. They won't be any bigger than 32 x 32 anyway.

But there's one thing I'm not getting now about these examples.

closest.enemy = e.enemy

You can change the instance name of objects? I had no idea... But how does this work with multiple towers that probably aren't aiming at the same thing?

And Matty, I'm afraid I have no idea how your example for clicking on one of the units is supposed to work. I got lost somewhere around here:
"CurrentIcon.IconObject is that of  Switch 1"
"if mouseclick on Switch 1 then 
DoNotAllowPress=0
For OtherIcons.IconObject=each IconObject
	If OtherIcons\AmIActive=1 and Handle(OtherIcons)<>Handle(CurrentIcon) then DoNotAllowPress=1:Exit 
next
If DoNotAllowPress=0 then
	do your standard action here for the new icon
endif 
endif 

Specifically, DoNotAllowPress and all the things you did with that confused me, and it almost sounds like once you've clicked on one, you can't click on any of the others...

I guess it might help if I name the game whose interface inspired me. What I want is to be able to click on any of the units and have a status thing come up on the sidebar, maybe with an upgrade or two, and then to be able to click on either another one or the ground and have the view change accordingly. The Bloons Tower Defense games, by Ninja Kiwi (requires Flash, I'm not sure what version, but 8 and up work for sure), is the game that brought about my approval of tower defense, and I want this interface to be something like that.

Anyway, I've decided about the rotations, and I see that First and Last don't really suit me. Thank you for your help so far!


gameproducer(Posted 2008) [#5]
Yes, but if you create the enemies in order of their coordinates and they're following a set path, I believe First would target the one at one end.

yes, if the path is straight... but if your path isn't a "line", then you gotta have distance thing.

You can change the instance name of objects? I had no idea...

please notice that "closest.enemy" is merely a pointer to a certain enemy.

In the beginning it's null, but then you make it to point to a specific object. I could have:
thing.enemy = e.enemy
anotherthing.enemy = thing.enemy
whatnot.enemy = e.enemy


and they would all point to the same object.

But how does this work with multiple towers that probably aren't aiming at the same thing?

Well, why couldn't they be aiming at the same thing? I think it would be allowed for different towers to aim & shoot the same thing: consider having 7 towers and only one enemy approaching: it would be pretty stupid if only one tower would aim & shoot them.

If you want to make sure they aren't aiming the same thing, then you'd need additional field defined in "type enemy", which would say that "somebody is aiming me". something like here:
type enemy
   field turretThatIsPointingMe.turret
   ... other fields
end type


then in the loop, you'd add a thing where you define which turret is aiming the enemy

Juts a quick code, so you could probably figure out better ways to handle things - but this should give you an idea.


gameproducer(Posted 2008) [#6]
Suggestion on doing the selection:

- create a gui element, where you define "clicked object"
type gui
   field selectedUnit.unit
end type


when you click units, then you would simply have something like:
function setSelectedUnit(gui.gui, unit.unit)
   gui\selectedUnit = unit
end function 


In the sidebar you'd have:
function showUnitInfoInSidebar(gui)
   show(gui\selectedUnit\health)
   show(gui\selectedUnit\armor)
   show(gui\selectedUnit\whanot)
end function 


What comes to 'selecting unit', I'm not totally sure, but I'd guess you would:
- need to figure out 'which unit was clicked'
- set the gui item to point to that selected object
- and then make sure sidebarinfo simply shows the selected object info


Tomas Khan(Posted 2008) [#7]
Well, why couldn't they be aiming at the same thing?

I agree; they should be able to aim at the same thing, but only if it's in range and would normally be targeted by both of them. I guess I was really asking how to manage more than one "closest target," as it would be possible to have every tower on the field choose a different target. With a For... Each... Next loop for the "closest targets"?

And about the selection thing... I'm totally mixed up right now. Maybe I'd better wait on that one until I start coding.

... But please do post if you think of something. I just may not have a lot of time to try to implement them for a little while.


Nate the Great(Posted 2008) [#8]
I was helping a friend make a similar game in bmax and we just used a variable called sellectedtower.
Each tower had its own number and since you couldn't have more that like... 200 of each tower, we checked to see which type of tower was selected by seeing if its number was inbetween 0-200 or 201-300 or 301-400... you get the point


Tomas Khan(Posted 2008) [#9]
So... when one clicked on a tower, selectedtower was adjusted to match the tower's number? And in this game, was it possible to change tower attributes (upgrades and such)? If so, how did you manage that? Did you say something like "If selectedtower = tower\no, [draw tower info here], If MouseHit(1) And [the mouse was in the 'button' area]" -- [b]And incidentally, what are good ways to tell it to find whether the mouse clicked in a certain area? Do you just do it with "MouseX() </> [insert x coordinate here]" and such, or do you put in a mouse image to use in ImagesOverlap, or can you do collision detection with the actual mouse, or should you put a point on the tip of the mouse and do collision detection with that, or what? Or do you make a button for that with a GUI command or something?

Sorry about all the questions jumbled together, but I haven't used the mouse much, and neither did Maneesh...

Thank you!


Nate the Great(Posted 2008) [#10]
woa... too many questions for me to read right now. sorry I don't have time.
Im sure this code will answer your questions... or create new ones :)
here is the code... I translated it to bb2d earlier so it should work in b+



sorry not heavily commented... hope it helps :D


Edit

you just click on the red or blue circles to select them to place towers of that color somewhere.

you can also click on previously made towers to change whether they are active of inactive

the major purpose of this code is to show how to access a tower's properties efficiently and effectivly... well my way isn't the most effiecient but it is simple and effective :)


Tomas Khan(Posted 2008) [#11]
That's okay. I don't have too much time for coding, either. But could you please just make up a little description for the variables you have in there? If I was sure just what each of them was doing, I think I could understand it fine without too many other explanations.

Thank you!


Nate the Great(Posted 2008) [#12]
ok I will have to wait till tommorrow to do that... sry don't have time :)


Tomas Khan(Posted 2008) [#13]
Like I said, that's okay. Thanks!

[EDIT] Oh, but I did have another question for the 'room' at large:
Question #4: How do you get an image with 16 different rotations to display the closest direction to an in-between angle? I wouldn't think that the only way to do it would be to use a super-long string of If statements asking if "player\angle >= 0 And player\angle < 22.5" and such. If someone knows of another way, could you tell me, please? Thank you! (This one might be done, but as I won't be able to tell until I've grasped the solution to another question, I won't confirm that yet.)


Nate the Great(Posted 2008) [#14]
ok I just copied and pasted the comments from my other program... now I really have to go so I can't post any more tonight. Here it is commented a little more.




Nate the Great(Posted 2008) [#15]
did this help or is it still confusing?

As for your other question... get the angle of the target. lets call that angle x. Now multiply by 16 and divide by 360 and put that part in an INT ( (x*16)/360) statement like that and blitz should round to the nearest whole number. Assuming you have an array with the rotations in it this would be the number you put into the array


Sauer(Posted 2008) [#16]
Ok for three, this is my suggestion:

I would store the x/y coordinates in an array, as well as a Boolean for activated or not. Then, on every mouse click, 'clear' the third column of the array that contains the 'active' variable (by setting them all to false), then, if the cursor is on the tower (in relation to x and y variables) change that variable to true.

So during your interface/update function, just scan the list for the variable that is true, then use the corresponding tower in your function.

I hope that made sense.


Nate the Great(Posted 2008) [#17]
Sauer... I never thought of that :D that would have made my old game so much simpler.

Sauer's suggestion is simpler and easier to understand but it depends on the way you want the user to place the towers. If you want them to be able to place them at any x and y then I think my method is the only practical way. If you want the towers to snap to a grid then I agree with sauer that arrays are the way to go.


Sauer(Posted 2008) [#18]
Yeah I think both are feasible and even a creative combination of each could work as well.

Now its up to you Mr. Khan.


Tomas Khan(Posted 2008) [#19]
I think the tower-ID method will work nicely enough for me. I haven't really used arrays much, although I have used them to get exact rotations. As for the Int((player\angle * 16) / 360) thing, though... As ATan2# can output negative angles, it seems like it could call for a negative frame/array-position. Would I have to add 180 to the resulting angle to get all positives, or should I plug in Abs(player\angle) for the equation and then have an extra If statement to help it decide which frame to use or something?

In other news, I've started coding! (So far, I've made it to the part where you choose the difficulty level, which at this point means Easy, and replaced the mouse. Any time now, I might actually start on the main loop.)


Nate the Great(Posted 2008) [#20]
no you have to add 16 if the output from the int statement is negative... I would suggest not worrying about that until you get to it.


Tomas Khan(Posted 2008) [#21]
Okay, now that I'm farther along now, I'll go through my other posts and strike out the things I'm fairly sure I understand now. *goes and does that*

And so I find that my main question now is about determining the closest enemy to each tower:

But how does this work with multiple towers that probably aren't aiming at the same thing?
...
I guess I was really asking how to manage more than one "closest target," as it would be possible to have every tower on the field choose a different target. With a For... Each... Next loop for the "closest targets"?


In other news, I can place towers! And they cost money!


Nate the Great(Posted 2008) [#22]
If that is all you are having trouble with then you are coming along well.
Just loop through all of the towers and all of the enemies and use the distance formula. Have a dummy type that you use and have a variable to determine what the closest distance so far.


Sauer(Posted 2008) [#23]
To find the closest enemy, use the distance formula. So, when you're scrolling through your tower types, scroll through enemies inside that loop, and check their distances with the formula ((x1-x2)^2+(y1-y2)^2)^.5, compare the results, and then set your sights on the one with the smallest result from that formula.


Tomas Khan(Posted 2008) [#24]
Ohhhhhhhhh! *lightbulb* You mean something like you check every enemy for distance within the tower loop and so you change it for every tower... and as the weapons aren't homing it doesn't matter which enemies are closest after that!

Okay, I'll see if I can get that going. ... Only I didn't know you could use carats to make BlitzPlus recognize exponents. You can? ... Well, it seems you can, so now I'll try it. Thank you!


Tomas Khan(Posted 2008) [#25]
Okay, now I've discovered another question. It has nothing whatsoever to do with interface or rotations, but it at least has a very little to do with targets...

Question 5 (or, as the other four were answered clearly enough, B1): Is it possible to determine whether an image collides with a line drawn with the Line command? And if so, how? It would be very, very helpful, as then I could attempt a line-based effect and actually have it do something. Oh, and I have a pretty involved background, which I believe could make ImageRectCollide less useful.

Thank you!


Ross C(Posted 2008) [#26]
Draw the line onto an image, then do an image to image collide? As long as your image has a backround colour, the same as the mask, it will only check for the pixels of the line.