Tower Defender
#1
Posted 25 February 2012 - 10:10 PM
I started making a tower defence game recently. I watched some tutorials, but they all had similar problems. It seems that achieving some things I want to implement is going to be tricky. So here are some questions.
My biggest puzzle is... How to detect which enemy is closest to the base? I don't mean just the distance from friendly base, I mean the one who travelled largest distance from the spawn. I was thinking about making a variable for all enemies, which increases by their current speed every fraction of a second. So there would be a huge number saying how much an enemy has travelled, even considering slowdown effects and different speeds. However, that could cause trouble if I wanted multiple monster spawns. Any ideas? Is it even reliable for a single spawn?
Targetting enemies. The tutorials show bullets. That's horrible. Bullets can be dodged. Assuming I already know which enemy it should target from question above... Let's say there are 3 enemies within tower range ("distance_to_object(tower)<some number). How to quickly pick one that has largest "variable" from question above? All tutorials I've seen show only attacking the one closest to the tower and not closest to the goal.
Finally... I am currently using PATHS to show the enemies how they should travel. Fair enough. But what if I want to have an enemy that spawns enemies? Upon creation, they would act as if they are at the beginning of the path and would go off the road, possibly of the screen. So do I have to find a way other than paths, or is there an easy way to make the enemies just continue where they spawn?
Thanks in advance
#2
Posted 25 February 2012 - 11:07 PM
However, I can answer one way of doing two anyways, not sure if it's the best. But here's what I do with this kind of thing:
with (Tower) //or freeze tower or whatever
{
global.currentHighest = noone //these are going to get continually wiped out, so there's no need to waste emory by putting them in a tower ;)
global.currentHighestNumber = -1
with (EnemyParent)
{
if (distance_to_object(other) < (insert amount))
{
if (distance_travelled < global.currentHighestNumber)
{
global.currentHighest = id
global.currentHighestNumber = distance_travelled
}
}
}
//now do something to currentHighest if it is not noone
}
#3
Posted 25 February 2012 - 11:52 PM
Anyway, I've been mostly using action icons and not the code so far, so I'm slightly confused about the code, but I'll likely figure it out later. But I'm concerned - will each tower calculate it's own "best target", picking only the mobs within it's range, when I use that code?
Edited by Gral92, 25 February 2012 - 11:53 PM.
#4
Posted 26 February 2012 - 12:10 AM
if !instance_exists(enemy_parent_obj) exit; // no need to target if no enemies
if distance_to_object(enemy_parent_obj)>range exit; // no need to check if noone is near enough
var ins;
ins = instance_nearest(x,y,enemy_parent_obj)
with(enemy_parent_obj)
if distance_to_object(other)<other.range // and the distance is less then the range of the tower
if ins.path_position < path_position // if this one is further along the path
ins = id;
target = ins; // you do now have the targetenemy spawning enemies:
// create it and set its position in the path to the same as its creator with( instance_create(x,y,small_foe_obj) ) path_position = other.path_position;
it is possible to find the meeting point for the enemy on the path and bullet, and then aim for that positionThe tutorials show bullets. That's horrible. Bullets can be dodged.
but then you might want to have a alarm that destroys the bullet when it should have hit and give its damage to its target if you want all to be hits .. accually, doing it that way makes it so you don't need any collision event at all.
#5
Posted 26 February 2012 - 01:19 AM
You could classify them yourself since you know their strenght and weaknesses. You could put a "rating" variable in each of the different ennemies. Let's say you have 10 different ennemi, the less dangerous is ID0 and the most dangerous is ID10.
After that, in your code you have one more thing to rely on for your AI to determine its next action. Like if you use a "distance to point" function in your conditions as well as the rating I suggested you, you therefore can priorise X ennemy over Y ennemy even if both actually are at the same distance from your base.
Edited by RangerX, 26 February 2012 - 01:20 AM.
#6
Posted 26 February 2012 - 11:18 AM
To make the player shoot at the nearest enemy, you can use this code:
image_angle = point_direction(self.x,self.y,instance_nearest(x,y,obj_enemy).x,instance_nearest(x,y,obj_enemy).y);
Now, one of our players aims at the nearest enemy.
To make sure that a turret aims at different kinds of enemies, set the other enemies' parent as your basic enemy.
I hope I taught you something about instance_nearest.
Other GMC users already learned you something about it, but you might still use this reply.
- GMRescue
#7
Posted 28 February 2012 - 10:25 PM
Now I've got a different problem. Not really relevant to tower defense. But it's weird!]
I used FoxInABox's code. Then I added this to the tower's Step code
if image_speed is equal to 1.5 if alarm[0] is equal to -1 set Alarm 0 to firerate execute code: target.alarm[0]=1;
Let me explain:
if image_speed is equal to 1.5 // image_speed changes to 1.5 when enemies are nearby. It works since the event does progress
if alarm[0] is equal to -1 // self-explanatory
set Alarm 0 to firerate // firerate is a tower variable for.. well, fire rate. It's 15 in this case
target.alarm[0]=1 // sets enemy alarm to 1. When their alarm hits 0, damage is done. That's my way to deal damage without projectiles
Expected result: When an enemy is nearby, every 15 loops, enemy's alarm 0 is set to 1 and damage is made
Actual result: Enemy takes damage once, then Alarm[0] of the tower is permanently stuck at 15, even when the enemy is out of range
It's like it keeps setting alarm 0 to 15 even though it shouldn't
Any clue about what's going on?
#8
Posted 28 February 2012 - 10:45 PM
#9
Posted 29 February 2012 - 12:06 AM
Edited by Gral92, 29 February 2012 - 12:28 AM.
#10
Posted 29 February 2012 - 01:44 AM
if (image_speed = 1.5)
{
if (alarm[0] = -1)
{
alarm[0] = firerate
}
}
target.alarm[0]=1; // just your old code that is fine.
Alternatively, if that does not work, in your alarm event, at the end, do
if (image_speed = 1.5)
{
alarm[0] = firerate
}
#11
Posted 29 February 2012 - 10:10 PM
Next problems... I made a range sprite, which is just a green semi-transparent circle.
First of all, how do I make it display on the tower when the mouse cursor is there? Earlier I was experimenting with just displaying it permanently and skipping the mouse part. I made a Draw Event and put draw_sprite_stretched there. But but but then the tower just disappeared, it got replaced by the range circle. I know I can just add draw_sprite for normal sprite for the tower there, but the towers are animated when an enemy is nearby and I have to specify subimage as one of the parameters of draw_sprite, and since it works like step, it's stuck at whichever frame I specify. So maybe not using Draw event will be better?
#12
Posted 29 February 2012 - 11:48 PM
you can use the build-in variables as the input for draw_sprite, that way you get the sprite you change to and animation frame..it's stuck at whichever frame I specify. So maybe not using Draw event will be better?
draw_sprite(sprite_index, image_index, x, y) // just copy it directly and it will animateif you want transparent, blending, scaling and rotation you will have to use:
draw_sprite_ext(sprite_index, image_index, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha)
if you want some kind of tower selection marker, then I would suggest you let some other object handle that, so when you click on a tower it just adds its id to a variable:
if you give all towers a variable that hold the range sprite it shall use, then you can do it like this:
tower create event:
range = range_spr;controll object draw event:
with( instance_position(mouse_x,mouse_y, tower_parent_obj) ) draw_sprite(range,0,x,y);so whenever the mouse is above a tower, then it will try to draw the sprite located in variable range of the tower, oh, and instance_position is looking for the parent object .. just a object you make the parent for all the towers .. makes it easier to find a tower
#13
Posted 20 March 2012 - 08:36 PM
Anyway, here's another problem:
Let's say I have buildControl object. Inside it, I want to have a "selected" variable that is equal to the instance of the selected tower. So if I click on a tower, it will be "selected". Similarly to how the "target" variable works few posts above. I need this to be able to upgrade the towers easily.
I'm assuming I will need to do with() again, but I'm sort of confused on how it works
#14
Posted 20 March 2012 - 08:48 PM
Global left click of buildControl:
theItem = collision_point(mouse_x,mouse_y,TowerOrWhatever,true,true)
if (theItem >= 0)
{
select = theItem
}
And whenever you want to change a variable in select just do select.variablename = whatever. But first check if select even exists
Edited by greep, 20 March 2012 - 08:49 PM.
0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users











