Enemy attack patterns
Monkey Forums/Monkey Programming/Enemy attack patterns
| ||
Hoping some of you brainy guys can help point me in the right direction here. I've been working on a bullet-hell shooter for some time now and I've created my own Enemy class that does various things. However, I would like to add an additional feature where I can set a parameter to have the enemy utilize the chosen attack pattern based on the parameter set. Only problem is, I'm not a brainy mathematician and haven't had much luck finding information on Google about attack patterns to use. For example, a sine-wave type attack move, circular 8 shape move, etc etc. So does anyone have anything of use to help this hapless person out? :) |
| ||
My first thought is that I would need to know whether single enemies or groups are involved. And secondly, should it control missile firing patterns also? There is the question of whether there is a constant relative motion to the player also. For example, is the player moving along at a steady or steady-ish pace while the enemy moves in circles about a particular point? What I'm saying is that the game is going to have a particular structure that the patterns will be variations on, and you can't really define the patterns until you know that structure. |
| ||
For example, a sine-wave type attack move, circular 8 shape move, etc etc. Those patterns can be easily achieved with sin/cosin in math - you just make the enemy position x + cos(angle)*radius, y + sin(angle)*radius and off you go :) (beware that x and y would be the center of the circle!) (for example to give a zig-zag movement while moving down, just use x + cos(angle)*radius,y and keep updanting angle from 0 to 360, and increasing y position) |
| ||
Thanks @Slotman. That's pretty much what I'm looking for, so I'll start playing with your examples later this evening. @Gerry: Though the player remains on screen, the background assets create the illusion of movement through a given level, but there's no actual scrolling happening. I run a timer, which triggers when enemies execute their attacks based on a predetermined time, ie the counter always starts at 0 at the beginning of the game, but say, the timer hits 200, then the first predetermined enemies will start their movements, which makes them appear to the user at a given point of illusionary movement through the level. I don't think that's really too much of an issue anyway, as Slotman's example pretty much provides the type of thing I'm after. I can provide more details if you are interested (this evening at home) and if that'll help, so let me know. |
| ||
Well, that is the sort of thing I was thinking about, My impression is that the enemy movement is a combination of a linear movement towards the player or more likely the horizontal or vertical line of the player, combined with an individual motion. I think it would simplify things if you added these together. For example, say the player is apparently moving up the screen, and an enemy is activated. It gets a linear movement downwards at the apparent speed that the player moves up. Superimposed on that, you put another motion, which could be anything. For example a circular motion. Then you would have: ' Start (a bit off screen) enemyBasePosition = ( xStart, yStart ) time = 0 ' Basic movement enemyBasePosition = ( xStart, yStart + VERT_SPEED * time ) ' Individual movement (there's a correct adjective for this that's on the tip of my tongue) angle = time / ROT_SPEED indivDelta = ( ROT_RADIUS * cos( angle ), ROT_RADIUS * sin( angle ) ' Actual position ( enemyBasePosition.x + indivDelta.x, enemyBasePosition.y + indivDelta.y ) So this enemy is moving down the screen, moving in circles around an object on your virtual background. Anyway, that's how I'd approach it. |
| ||
You could use a simple way point system: Also Samah loves bullet-hell games, he started(!!!) one for the Community Project Monkey Touch: http://www.monkey-x.com/Community/posts.php?topic=7479&app_id=231 (It takes a bit to load...scroll down for DanMonkey) http://code.google.com/p/monkey-touch/ |
| ||
Guys, this is fantastic thanks! @Gerry, this is pretty much exactly what I want to do with the "regular" enemies, and @therevills, that is EXACTLY what I want to do with bosses. Killed two birds with one stone there, thanks a mil! I'll have a look at Samah's one tonight and hopefully be implementing your awesome suggestions over this weekend. At the moment, my enemy class receives parameters such as X movement and Y movement in floats, so they're pretty basic right now where they have a start x/y and a move x/y. Adding the above suggestions will add loads of awesome movement patterns over the regular straight movement of the current system. The boss class will use @therevills waypoint system, so thanks guys! PS. This is why the Monkey community rocks! Almost always is there someone that can help/suggest useful information. |
| ||
What I did for Terminal 2 is a flight system that uses a data passing node system, a path would have x number of nodes(waypoints) each node would also have a varied set of attributes and as an enemy or unit flew along the path and reached a node the node would then pass new data to the unit, things like speed, turn rate, next node and fire patterns get passed, this allows me to easily map out a path and then edit the nodes to add fire patterns. There are tons of ways you can go about this tho. |
| ||
@Slotman and @Gerry: implemented your suggestions and they work a treat thanks! Next step is to implement @therevills' waypoint idea for a main boss. Until then though, I need to first do more attack waves before the boss class can be done and tested :) Again, thanks guys! |
| ||
This problem bothered me the previous week so today I have made a prototype. It would be a good place to start studying and experimenting.Strict Import mojo Class EnumWaveStyle Const Straight:Int = 0 Const Zigzag:Int = 1 'Other wave styles for extension: 'I now lazy to add more implementations 'Waypoint (i.e. follow waypoints) 'Boss (i.e. not going away until is dead) End Class Wave Field name:String ' for debugging purposes Field enemies:List<Enemy> ' a list of all the enemy objects Field finished:Bool = False ' quick way to determine if the wave is to be deleted Field waveStyle:Int ' the preferred style of this wave Method New() enemies = New List<Enemy> ' the position of the wave Local position:Float = Rnd(0, DeviceWidth()) ' create 10 enemies (hardcoded) For Local i:Int = 0 To 10 Local e:Enemy = New Enemy e.x = position ' random x position of the wave e.y = -(i * 60) ' distance between enemies is 60 enemies.AddLast(e) Next ' determine the style of the wave waveStyle = Int(Floor(Rnd(0.0, 2.0))) End Method Update:Void() ' a simple variable used only in the zigzag effect trick Local counter:Int = 0 For Local e:Enemy = Eachin enemies e.Update() ' quicky way to move enemies based on their style ' very ugly way, i hope I will find better examples :) If waveStyle = EnumWaveStyle.Zigzag Local phase:Float = counter*45 Local magnitude:Float = 5 Local speed:Float = 0.25 e.xs = Sin((Millisecs() + phase)*speed) * magnitude End ' quicky way to determine if wave is finished ' that means that if all enemies are out of the ' screen bounds only then entire wave is going extinct If e.y <= DeviceHeight() finished = False Else finished = True End counter += 1 Next End Method Render:Void() For Local e:Enemy = Eachin enemies e.Render() Next End End ' Very simple enemy class Class Enemy Field x:Float Field y:Float Field xs:Float Field ys:Float Method New() ys = 2.25 End Method Update:Void() x += xs y += ys End Method Render:Void() DrawOval(x-5, y-5, 10, 10) End End ' very simple stopwatch implementation Class Stopwatch Field Interval:Float Field Elapsed:Float Method New() Interval = 1 End Method Tick:Bool() Local currentTime:Float = Millisecs() / 1000 If currentTime - Elapsed >= Interval Elapsed = currentTime Return True End Return False End End Class Game Extends App Field waves:List<Wave> Field watch:Stopwatch Method OnCreate:Int() SetUpdateRate(60) Seed = Millisecs() ' this is a timer to spawn waves ' and that means in every 5 seconds ' a new wave will be added watch = New Stopwatch watch.Interval = 5 ' create the list object but ' do not add any waves yet ' this will be done based on timing waves = New List<Wave> Return 0 End Method OnUpdate:Int() ' when the timer reaches the required ' interval then a new wave will be added If watch.Tick() Then Local w:Wave = New Wave ' for debugging purposes a name is given this is though optional w.name = "Wave"+Int(watch.Elapsed) Print("Spawned wave: " + w.name) waves.AddLast(w) End ' if there are any waves in the list ' they are going to be updated If waves.Count() > 0 For Local w:Wave = Eachin waves w.Update() ' when a wave is finished it means ' is not needed anymore and is going to be removed If w.finished Print("Removed wave: " + w.name) waves.RemoveEach(w) End Next End Return 0 End Method OnRender:Int() Cls ' the rendering of the waves If waves.Count() > 0 For Local w:Wave = Eachin waves w.Render() Next End Return 0 End End Function Main:Int() Local game:Game = New Game Return 0 End |