Welcome, Guest. Please Login or Register.  • Help
SMF Underground
+ SHMUP-DEV » SHMUP DEV FORUMS » Assistance
|-+ Attack Patterns

Pages: [1]   Go Down
0 Members and 1 Guest are viewing this topic. Topic Tools  
Read December 29, 2005, 12:43:55 AM #0
Matt McFarland

Attack Patterns

I was thinking I could make a spline for every attack pattern.  If I did this, then I would draw them all out.. But if I want them to behave a certain way.. Like go down... shoot every where, fly back really fast.  Would it be wise to use splines in EVERYTHING?  If not, what other ways could I make them attack without using splines and still have a smooth effect?
« Last Edit: December 29, 2005, 01:02:30 AM by Matt McFarland »

<a href="http://www.mattmcfarland.com/flash/myFlashSig.swf" target="_blank">http://www.mattmcfarland.com/flash/myFlashSig.swf</a>
Offline  
Read December 29, 2005, 09:45:25 AM #1
oNyx

Re: Attack Patterns

One possible solution is to use a list with pathes. Like A->B, B->C, C->D (those letters are the end points). And you could have for example speed modifier events associated with those end points. This way you would get rather smooth speed transitions without going too much into detail (faster to create).

So, enemies spawn with some specified speed and get some acceleration value (positive, negative or zero) from A, then they go to B. Once there they adjust the acceleration value etc.

That would be one way. Editor wise it could be done like that or with speed values instead of acceleration values for the end points (the spawn point wouldnt be special anymore). The acceleration could be then determined by taking the length of a path and interpolation, but its more complicated and it doesnt really help much in the level design stage afaict.

The end points could be also used for switching attacking on/off.
Offline  
Read December 29, 2005, 09:54:25 AM #2
SI_78

Re: Attack Patterns

Maybe rather than 1 spline to control the entire movement for an attack pattern - you could make up the attack pattern out of lots of different smaller components giving you an attack script for that unit type?

So you'd place all your enemies on the map, then when their about to come on screen they start their scripts.

So for example for red ships you might have.

; Command name, duration (if applicable and in seconds).
MOVE_STRAIGHT_DOWN, 1
FIRE_RANDOM, 0.5

or

ZIG_ZAG_DOWN, 1
FIRE_AT_PLAYER, 0.5
LOOP,


Anyways it's just some ideas - I hope this helps :-)





Offline  
Read January 04, 2006, 05:25:13 PM #3
Matt McFarland

Re: Attack Patterns

Maybe rather than 1 spline to control the entire movement for an attack pattern - you could make up the attack pattern out of lots of different smaller components giving you an attack script for that unit type?

So you'd place all your enemies on the map, then when their about to come on screen they start their scripts.


This seems very interseting, but how would this be done?  I mean.. how would you create a script like this?  I can see your idea as a good one, but my main problem is implementation. 


<a href="http://www.mattmcfarland.com/flash/myFlashSig.swf" target="_blank">http://www.mattmcfarland.com/flash/myFlashSig.swf</a>
Offline  
Read January 04, 2006, 10:33:31 PM #4
kemical

Re: Attack Patterns

the way I'm probably going to go about attack patterns is similar to a waypoint system,, the enemy will have to travel from it's starting location to the desired ending location, but instead of going in a direct line it's x and y speed will be gradually increased or decreased so that arcing and curves happen.
once the enemy is in a certain radius of the destination point it will then move onto any other points, but I'd also have properties for delays and stuff. 
Ontop of all this you could also add in some sin/cos expressions that make the enemy move in loops and spirals etc..

The reason I'm doing it this way is so that I can drop in control point objects in the level editor, and when initializing the enemies they will have their lists of control points to use, along with their desired starting velocity and accelleration/dec speeds, I think that would be simpler than programming in a spline/bezier curve type of thing, and also easier to visualize in a tile/level editor when placing enemies.
Offline  
Read January 05, 2006, 10:37:12 AM #5
Matt McFarland

Re: Attack Patterns

My bsplines look great for their introduction patterns.  But they don't work best when the enemy attacks.  The main problem is speed control along a bezier curve.  Although speed changes look very good when they fly in, it doesnt do well when they attack.  Also, each enemy I have I want to attack differently to add flavour to the game. 

I'm having some problems visualizing different wayst o bring in attacks.

I have read that there is a way to get the guys fly to certain points then start curving, and going to another point.  Do you have a code snippet to do this?

Thanks!


<a href="http://www.mattmcfarland.com/flash/myFlashSig.swf" target="_blank">http://www.mattmcfarland.com/flash/myFlashSig.swf</a>
Offline  
Read January 10, 2006, 10:23:39 AM #6
sloaned

Re: Attack Patterns

In my code I've setup a list of joined bezier curves for the enemy movement. Each bezier curve segment in the list has a time in milliseconds assigned to it so you can slow down or speed up specifci segments of the enemies path.

Each time around the game loop I call an enemy update function which moves the sprite to an interpolated position along the appropriate bezier curve in the list, once the end of one curve has been reached it starts interpolating the position using the next curve in the list. If there are no more bezier curves in the list, the enemy sprite is destroyed and the memory it was using cleared up.

I haven't done a great deal of work on my enemy attacks as yet, but heres my thoughts.

Some attacks will be solely on a timer (eg. shoot blindly every 500ms). Others are setup as events (eg. 5 seconds after the sprite is created, shoot something, 10 seconds after the sprite is created, shoot a different type of bullet). This works okay for your typical run of the mill enemy that flies off the screen never to be seen again. As for end of level boss type characters that doesn't disappear until the player destroys them, all I'd be thinking i'd need to do is loop the event timer once its reached the last attack pattern so it starts over again.

Hopefully that made some kind of sense.
Offline  
Read January 10, 2006, 10:45:54 AM #7
Matt McFarland

Re: Attack Patterns

In my code I've setup a list of joined bezier curves for the enemy movement. Each bezier curve segment in the list has a time in milliseconds assigned to it so you can slow down or speed up specifci segments of the enemies path.

Each time around the game loop I call an enemy update function which moves the sprite to an interpolated position along the appropriate bezier curve in the list, once the end of one curve has been reached it starts interpolating the position using the next curve in the list. If there are no more bezier curves in the list, the enemy sprite is destroyed and the memory it was using cleared up.

It's uncanny but I do exactly the same thing you're doing!!  Almost word for word.. heh..t I only have one attack pattern so far.  It's...guess... its a couple of bezier curves!!!  It does look pretty good for what it is, but I would like to add more of a variety..


<a href="http://www.mattmcfarland.com/flash/myFlashSig.swf" target="_blank">http://www.mattmcfarland.com/flash/myFlashSig.swf</a>
Offline  
Read January 10, 2006, 10:56:49 AM #8
sloaned

Re: Attack Patterns

It's uncanny but I do exactly the same thing you're doing!!  Almost word for word.. heh..t I only have one attack pattern so far.  It's...guess... its a couple of bezier curves!!!  It does look pretty good for what it is, but I would like to add more of a variety..

lol. im a lazy bugger and it just seemed the easiest way to do it. one of my friends is working on a 2d/3d scroller at the same time and i asked him how he did his enemy movement. he was using text-based scripts for each enemy eg. TURN RIGHT, FORWARD 200, (seems reminiscent of LOGO from my primary school Apple IIe days) seems a bit painful for my liking. you'd have to write it, run the game and see what it looked like, tweak it over and over again.

i just visually design a nice series of linked curves in "splinemagic", it spits out 8 integers defining each segment of the curve, i stick them into my code and ta-da, theres my enemies path. then all i have to do is give each segment a time in milliseconds. also, rather than designing a new curve for every single enemy i just make the curves all start at 0,0 and then apply an x,y offset when i create the enemy.
Offline  
Read January 15, 2006, 05:57:04 PM #9
Matt McFarland

Re: Attack Patterns

Honestly, I'm using specific attack patterns for each type of attack..

First.. I have an attack manager that's a type (or class in C)

Code: (blitzmax)
Type AttackController
Field EnemySelected
Function CreateAttackGroup()
'Parse through enemy list and pick a number at random
'Select numbers adjacent if they are available
'Send strike group to attack player

End Function
Function DoWaveAttack()
Local selection = Rand(1,Maxenemies)
Local selector
Local player:TPlayer = TPlayer(PlayerList.Last())
For Local Enemy:TEnemy = EachIn EnemyList
Selector:+1
If selector = selection and enemy.phase = formation
enemy.target_x = enemy.x
enemy.phase = WaveAttack
End If
Next
End Function
Function DoChargeAttack()
Local selection = Rand(1,MaxEnemies)
Local selector
Local player:Tplayer = TPlayer(PlayerList.Last())
For Local Enemy:Tenemy = EachIn EnemyList
Selector:+1
If selector = selection and Enemy.phase = formation
   enemy.target_X = player.x
   enemy.phase = ChargeAttack
EndIf
Next
End Function
Function DoSingleAttack()
'Just pick a random enemy and send him to attack.
'This is the dive attack, always is..
'point 0 = enemyassignedx,y
'point 2 = enemyassignedx,y
'point 1 = player x - 600(make it random), y would be 600
'point 1 = player x + 600(make it somewhat random), y would be 600
Local selection = Rand(1,MaxEnemies)
Local selector
  Local Player:TPlayer = Tplayer(PlayerList.Last())
  Local Target_Y = Rand (400,600)
For Local Enemy:Tenemy = EachIn EnemyList
selector:+1


Local Target_p1x:Float
Local Target_p3x:Float
Local Target_Y:Float
If selector = selection and Enemy.phase = formation
  Select Rand(1,2)
  Case 1
  Target_p1x = player.x - Rand(600,800)
  Target_p3x = player.x + Rand(600,800)
  Case 2
  Target_p1x = Player.x + Rand(600,800)
  Target_p3x = Player.x - Rand(600,800)
  End Select
Target_Y = Rand(400,600)
enemy.t = 0
Enemy.Target_p1x# = Target_p1x
Enemy.Target_p3x# = Target_p3x
Enemy.Target_p1y# = Target_Y
Enemy.Target_p3y# = Target_Y
Enemy.DiveX = Enemy.assignedx
Enemy.DiveY = Enemy.assignedy
Enemy.phase = SingleAttack
Enemy.Singleattackphase = 1

                   EndIf
Next
End Function
Function DoSpecialAttack()
'Send an enemy to do it's special attack move. based on enemy classID
End Function
Function Update()
'Get level settings, then randomly perform attacks.
If MilliSecs() > AttackClock and CountList(playerlist) <> 0
If Rand(1,100) > FormationAttackChance Then AttackController.CreateAttackGroup()
If Rand(1,100) > SingleAttackChance Then AttackController.DoSingleAttack()
If Rand(1,100) > ChargeAttackChance Then AttackController.DoChargeAttack()
If Rand(1,100) > SpecialAttackChance Then AttackController.DoSpecialAttack()
If Rand(1,100) > WaveAttackChance Then AttackController.DoWaveAttack()
If CountList(enemylist) > 4 Then AttackClock = MilliSecs()+1000
If CountList(enemylist) < 5 Then AttackClock = MilliSecs()

enemymax = CountList(enemylist)
End If
End Function
End Type

It's kinda big, and right now I haven't programmed a special attack.
You'll notice that it randomly fires a random command unto a random enemy in the enemy list.
Here's what happens inside the enemy's code in respect to what phase it is told it is in!

Code: (blitzmax)
Method DoSingleAttackRun(obj:TEnemy)
        Local enemy:TEnemy = obj:TEnemy
        Select enemy.SingleAttackPhase
        'Case 1, drop down a little bit
        Case 1
enemy.DiveY:+1
enemy.x:Float = (enemy.DiveX*(1-enemy.t)^3 + 3*enemy.DiveX*(1-enemy.t)^2*enemy.t + 3*enemy.DiveX*(1-enemy.t)*enemy.t^2 + enemy.DiveX*enemy.t^3)
enemy.y:Float = (enemy.DiveY*(1-enemy.t)^3 + 3*enemy.DiveY*(1-enemy.t)^2*enemy.t + 3*enemy.DiveY*(1-enemy.t)*enemy.t^2 + (enemy.DiveY+50)*enemy.t^3)

enemy.t:+.05 * Delta.time()

  enemy.nextpointx:Float = (enemy.DiveX*(1-enemy.t)^3 + 3*enemy.DiveX*(1-enemy.t)^2*enemy.t + 3*enemy.DiveX*(1-enemy.t)*enemy.t^2 + enemy.DiveX*enemy.t^3)
enemy.nextpointy:Float = (enemy.DiveY*(1-enemy.t)^3 + 3*enemy.DiveY*(1-enemy.t)^2*enemy.t + 3*enemy.DiveY*(1-enemy.t)*enemy.t^2 + (enemy.DiveY+50)*enemy.t^3)

enemy.Angle = calcAngle2D( enemy.x,enemy.y,  enemy.nextpointx,enemy.nextpointy)
enemy.x:+ Cos(enemy.Angle)* Delta.time()
enemy.y:+ Sin(enemy.Angle)* Delta.time()
If enemy.t => .09  Then  Enemy.DivingX = Enemy.x ; Enemy.DivingY = Enemy.y ; enemy.t = 0 ; enemy.SingleAttackPhase = 2
'Case 2, dive and curve
        Case 2
enemy.x:Float = (enemy.DivingX*(1-enemy.t)^3 + 3*enemy.Target_p1x*(1-enemy.t)^2*enemy.t + 3*enemy.Target_p3x*(1-enemy.t)*enemy.t^2 + enemy.DivingX*enemy.t^3)
enemy.y:Float = (enemy.DivingY*(1-enemy.t)^3 + 3*enemy.Target_p1y*(1-enemy.t)^2*enemy.t + 3*enemy.Target_p3y*(1-enemy.t)*enemy.t^2 + (enemy.AssignedY+50)*enemy.t^3)

enemy.t:+00001 * Delta.time()     *.0035
  enemy.nextpointx:Float = (enemy.DivingX*(1-enemy.t)^3 + 3*enemy.Target_p1x*(1-enemy.t)^2*enemy.t + 3*enemy.Target_p3x*(1-enemy.t)*enemy.t^2 + enemy.DivingX*enemy.t^3)
enemy.nextpointy:Float = (enemy.DivingY*(1-enemy.t)^3 + 3*enemy.Target_p1y*(1-enemy.t)^2*enemy.t + 3*enemy.Target_p3y*(1-enemy.t)*enemy.t^2 + (enemy.AssignedY+50)*enemy.t^3)


enemy.Angle = calcAngle2D( enemy.x,enemy.y,  enemy.nextpointx,enemy.nextpointy)
enemy.x:+ Cos(enemy.Angle)* Delta.time()
enemy.y:+ Sin(enemy.Angle)* Delta.time()
If enemy.t => 1  Then  Enemy.ReturnX = Enemy.x ; Enemy.ReturnY = Enemy.y ; enemy.t = 0 ; enemy.SingleAttackPhase = 3
'Case 3, return home.
        Case 3
enemy.x:Float = (enemy.ReturnX*(1-enemy.t)^3 + 3*enemy.Assignedx*(1-enemy.t)^2*enemy.t + 3*enemy.Assignedx*(1-enemy.t)*enemy.t^2 + enemy.Assignedx*enemy.t^3)
enemy.y:Float = (enemy.ReturnY*(1-enemy.t)^3 + 3*(enemy.AssignedY)*(1-enemy.t)^2*enemy.t + 3*(enemy.AssignedY)*(1-enemy.t)*enemy.t^2 + (enemy.AssignedY)*enemy.t^3)

enemy.t:+.03 * Delta.time()

  enemy.nextpointx:Float = (enemy.ReturnX*(1-enemy.t)^3 + 3*enemy.Assignedx*(1-enemy.t)^2*enemy.t + 3*enemy.Assignedx*(1-enemy.t)*enemy.t^2 + enemy.Assignedx*enemy.t^3)
enemy.nextpointy:Float = (enemy.ReturnY*(1-enemy.t)^3 + 3*(enemy.AssignedY)*(1-enemy.t)^2*enemy.t + 3*(enemy.AssignedY)*(1-enemy.t)*enemy.t^2 + (enemy.AssignedY)*enemy.t^3)

enemy.Angle = calcAngle2D( enemy.x,enemy.y,  enemy.nextpointx,600)
enemy.x:+ Cos(enemy.Angle)* Delta.time()
enemy.y:+ Sin(enemy.Angle)* Delta.time()
If enemy.t => 1  Then enemy.phase = formation
        Case 4
enemy.x:Float = (enemy.ReturnX*(1-enemy.t)^3 + 3*enemy.Assignedx*(1-enemy.t)^2*enemy.t + 3*enemy.Assignedx*(1-enemy.t)*enemy.t^2 + enemy.Assignedx*enemy.t^3)
enemy.y:Float = (enemy.ReturnY*(1-enemy.t)^3 + 3*(enemy.AssignedY)*(1-enemy.t)^2*enemy.t + 3*(enemy.AssignedY)*(1-enemy.t)*enemy.t^2 + (enemy.AssignedY)*enemy.t^3)

enemy.t:+.01 * Delta.time()

  enemy.nextpointx:Float = (enemy.ReturnX*(1-enemy.t)^3 + 3*enemy.Assignedx*(1-enemy.t)^2*enemy.t + 3*enemy.Assignedx*(1-enemy.t)*enemy.t^2 + enemy.Assignedx*enemy.t^3)
enemy.nextpointy:Float = (enemy.ReturnY*(1-enemy.t)^3 + 3*(enemy.AssignedY)*(1-enemy.t)^2*enemy.t + 3*(enemy.AssignedY)*(1-enemy.t)*enemy.t^2 + (enemy.AssignedY)*enemy.t^3)

enemy.Angle = calcAngle2D( enemy.x,enemy.y,  enemy.nextpointx,enemy.nextpointy)
enemy.x:+ Cos(enemy.Angle)* Delta.time()
enemy.y:+ Sin(enemy.Angle)* Delta.time()
If enemy.t => 1  Then enemy.phase = formation

    End Select
   
End Method
Method DoWaveAttack(obj:TEnemy)
Local enemy:TEnemy = obj:TEnemy
If enemy.y < 700
enemy.y:+1.5 * Delta.time()
enemy.x = enemy.x + Sin(time*4) * 3
End If
If enemy.y > 700
enemy.y=-100
Enemy.ReturnX = Enemy.x ; Enemy.ReturnY = Enemy.y ; enemy.t = 0 ; enemy.SingleAttackPhase = 4
enemy.phase = singleattack
End If
End Method
Method DoChargeAttack(obj:TEnemy)
Local enemy:TEnemy = obj:TEnemy
enemy.Angle = calcAngle2D( enemy.x,enemy.y,  enemy.Target_x,800)
If enemy.y < 700
enemy.x:+ Cos(enemy.Angle)* Delta.time() * 3
enemy.y:+ Sin(enemy.Angle)* Delta.time() * 3
End If
If enemy.y > 700
enemy.y=-100
Enemy.ReturnX = Enemy.x ; Enemy.ReturnY = Enemy.y ; enemy.t = 0 ; enemy.SingleAttackPhase = 4
enemy.phase = singleattack
End If
End Method
« Last Edit: January 15, 2006, 06:08:55 PM by Matt McFarland »

<a href="http://www.mattmcfarland.com/flash/myFlashSig.swf" target="_blank">http://www.mattmcfarland.com/flash/myFlashSig.swf</a>
Offline  
Read January 15, 2006, 06:27:26 PM #10
Matt McFarland

Re: Attack Patterns

The tabbing(nesting) doesnt look like it does in my IDE, probably something to do with copy pasting, etc Tongue


<a href="http://www.mattmcfarland.com/flash/myFlashSig.swf" target="_blank">http://www.mattmcfarland.com/flash/myFlashSig.swf</a>
Offline  
Pages: [1]   Go Up
Jump to:  

Page created in 0.143 seconds with 19 queries.