moving emeny with its own (moving) collision detector - changing speed query
Hello,
I think this is my 8th question inside a week, I wonder if I'm going for some kind of record! Apologies, I am checking the forum for solutions prior to posting, if I hadn't been I'd have posted around 30 questions by now!
Right, so in this game I'm working on I have some enemies that get spawned from a prototype on a regular basis, they appear from the right hand side of the screen and move horizontally towards the left. they move at a pre-determined speed, if they collide with a weapon they slow down to about a tenth of normal speed and calculations of health and damage occur, if the weapon is destroyed or removed - they proceed back up to normal speed, and if the enemy's reaches 0 health, it gets destroyed. Nice and simple.
And it was until I started messing about with refined collision detection. I've previously posted about setting this up for my weapons -
http://forums.gamesalad.com/discussion/81412/another-collision-detection-query#latest
I sorted that out in the end, weapon gets generated, as does an additional, smaller actor that acts as collision detector. They are linked by a common id attribute number and conditions that destroy them both if the weapon destroyed. Frankly that was quite easy as my weapons, once deployed, remain stationary. Not so for my enemies.
So far I can generated my enemy and it's accompanying collision detector actor, as with the weapons I've linked them together using a common id number, but the movement is giving me problems. The two must stay exactly together, moving at precisely the same speed. Obvious I can get them to appear at the same time and start moving at the same speed at the same time, but the reduction of speed when a weapon is encountered is giving me trouble.
My enemy collision detector actor is going to be the one that detects the weapon and slows down, I need a way of getting it to relay that to the enemy actor itself in order for it to follow suit. And of course, it also needs to be able to tell the enemy to speed up again if the weapon is no longer blocking it's path.
From the last post I found a way to get the collision detector to specify when a weapon needs to be destroyed, but I can't figure out how the enemy collision detector can tell the enemy actor what speed to move at.
Any ideas?
Best Answer
-
tatiang Posts: 11,949
For that, I would create a table and use the self.actorID as the table row. Set the speed in the first column of the table row for that pair, constrain each actor's speed to that table cell value, and change it as needed. That is, if an actor changes the table value, the other actor will instantly change as well since it's constrained to it. It can be a little tricky in the PC version of Creator to do this since rules don't support numeric expressions on the left side so if you need help, let me know.
New to GameSalad? (FAQs) | Tutorials | Templates | Greenleaf Games | Educator & Certified GameSalad User
Answers
Could you sum up your post as "how do I link two objects together so that one always follows the other?", if that is the question then you can simply constrain one actor to another actor using the Constrain behaviour.
Hi Socks - yes, that is in essence what I want to do. I can understand the constrain command if I had a singular character, but I'm dealing with an enemy and a collision detection actor are being spawned from a prototype every 2 seconds by a control. I can easily spawn them in the same location but I can't see how to constrain the speed of the two for each instances spawned? Does that make sense or am I being daft (again)?
Right - after a lot of head scratching I've got a possible solution. I can't see the constrain attribute behaviour working for this for reasons mentioned in my previous post.
I've gone for an old-school approach - the four state binary logic gate.
I'm using two game attributes set as integers - I've called them enemyfast and enemyslow, both must be set to 0 at the start of the game. Here is how it works;
1) Enemy gets generated
2) Collision detector rules
If collision with a weapon IS NOT detected;
Am I moving fast?
If collision with weapon IS detected;
Am I moving fast?
To paraphrase, the collision detector sends it's ID to game.enemyfast when it's going fast and sends it to game.enemyslow when it's going slow.
3) Enemy actor rules
So the enemy actor has some rules looking out for when either game.enemyfast and game.enemyslow equal or, just as importantly, do not equal self.enemyid.
If both game.enemyfast AND game.enemyslow DO NOT equal self.enemyid;
If game.enemyslow = self.enemyid but game.enemyfast does not;
If game.enemyfast = self.enemyid but game.enemyslow does not;
If both game.enemyfast AND game.enemyslow DO equal self.enemyid;
If you're wondering why that last condition should ever come about, I did think about having the collision detector reset game.enemyfast AND game.enemyslow to 0 a fraction of a second after a change in status of either attribute, but I figured that would be less efficient. There could be around 30 enemies on screen at once, that's an extra timer going off with every change of status. I've a feeling either GS would start to get confused and miss collisions or the program would grind to a halt once a lot of enemies came into play!
So I've planned it all out on paper, I just have to put the commands into Gamesalad now and see if it actually works! I'm actually dreading this bit, seriously, if anyone here has an easier solution - now would be a great time to mention it!
If you want to link two spawned actors together, increase an integer game attribute (e.g. game.spawnID) by one right before spawning both actors and then in each spawned actor's rule list at the top and outside of any rules, change self.ID (integer) to game.spawnID.
You can then use self.ID in rule conditions to manipulate both actors at once. For example, if the spawning actor is to be destroyed (forgive me for not reading both of your long posts but I jumped in here at the end...), it could change game.destroyID to its own ID or some other number you choose and each spawned actor could have a rule that says If self.ID=game.destroyID then Destroy Actor.
New to GameSalad? (FAQs) | Tutorials | Templates | Greenleaf Games | Educator & Certified GameSalad User
Hi Tatiang
That idea was raised in one of my previous questions and that proved useful for sending a single instruction as you say, like destroying a linked actor, but I'm finding it's not versatile enough on it's own to control changes of speed, particularly in the case of actors spawned from prototypes.
Without wanting to post something too long and rambling (again) - here is the problem;
Example,
a simple project with some blocks randomly placed around.
A controller that spawns 2 actors from prototypes every 2 seconds. We'll call the prototypes ActorA and ActorB. We want them to spawn in the same place and move together. With every spawning, we increment an attribute called actorID by 1 and assign that number to the newly spawned pair. So the first instances of ActorA and ActorB have the self.actorID of 1, the second pair would be 2, and so forth.
So far, easy.
When they spawn, each of the instances of Actor A and B both get the instruction to move in the same direction and at the same speed, however, if ActorA collides with a block, it needs to move slower, and it needs to somehow communicate that slowdown instruction to ActorB. And inversely, when it is no longer colliding with a block it needs to return to normal speed and again, tell ActorB to follow suit.
I can't see a simple way of implementing some foolproof rules to force all instances of Actor B to travel at the same speed as their associated instance of ActorA.
My idea in my previous post required a game attribute for going fast and one for going slow. Having two attributes immediately made the exercise more complicated.
Hello again Tatiang
I think I've managed to come up with a modified and slightly simplified version of my solution that does only use the unifying game attribute.
When ActorA hits a block a game attribute gets set to ActorA's ID number - but only for a fraction of a second then it's reset back to zero, long enough for ActorB to register it but not too long as to mess up collision detection for the other similar actors. Most crucially, the above only happens once when a collision occurs - prolonged collision does not keep triggering the signal, the signal won't get sent again until ActorA finds it's not longer colliding, then it sends it again to notify ActorB of the state of state. It is like a toggle switch. Thankfully far less complicated than the binary logic gate idea I proposed.
However, I reckon in terms of efficiency, your table solution is interesting. I think I can get my head around the rules that would manipulate it, but wouldn't every pair of actors spawned need to generate a new row, or would you simply have a guess as to the most actors you're ever likely to need and pre-populate the table in advance?
In terms of efficiency of execution, do you think my idea, where literally every instance of a collision and end of collision would result in a fraction of a second timing event, would be unfavourable to your idea where table data is being constantly being referenced?
I'm intrigued now! I'm assuming you'd go for constraining to a table field over timing every time?
Okay Tatiang, I officially like your suggestion a lot more than mine now, seems to be super responsive! I think that the constraining to the table value is the best solution! I knew it wasn't as simple a matter of just using the constrain command - but thanks for providing a means to use constrain in conjunction with the tables, brilliant stuff!
You're welcome!
New to GameSalad? (FAQs) | Tutorials | Templates | Greenleaf Games | Educator & Certified GameSalad User