Updating Attributes
specialist_3
Member Posts: 121
Hi All,
I have ran into a problem with my shooter game. I have a gun which shoots different types of bullets. Different enemies need different bullets to be killed. Suppose there is a werewolf and he can only be killed by a silver bullet. Gold bullet won't work on him. My gun fires when I press space. I can choose different bullets by pressing 1,2,3 etc. When I fire a silver bullet and it collides with the enemy actor, I do an attribute comparison (RULE check) and if 1 = 1, the enemy and bullet are destroyed. If it is not equal the bullet simply passes through. I have a global attribute called Bullet.Type (1,2,3 etc) This is where the challenge starts....
Suppose,
Bullet.Type
Bronze bullet = 1
Silver bullet = 2
Gold bullet = 3
When I fire a gold bullet and then fire a silver bullet (1 trailing the other), when the gold bullet hits the werewolf, the actors die. This is because when the silver bullet (second fire) is shot, it changes the attribute of the gold bullet (at present 3) to silver = 2. How do I ensure that each bullet has its own bullet.type value such that fired bullets retain their bullet.type value.
Vice versa, when a silver bullet is fired and then followed by a gold bullet, the silver bullet does not kill the werewolf because now this time round, the bullet.type global attribute has changed to 3.
I know this has probably got to do with playing around with Constrain Attributes vs Change Attributes behavior but I am not able to get them to work properly. Or is there some other efficient way to sort this out? Can anyone guide me through this please?
Cheers!!
I have ran into a problem with my shooter game. I have a gun which shoots different types of bullets. Different enemies need different bullets to be killed. Suppose there is a werewolf and he can only be killed by a silver bullet. Gold bullet won't work on him. My gun fires when I press space. I can choose different bullets by pressing 1,2,3 etc. When I fire a silver bullet and it collides with the enemy actor, I do an attribute comparison (RULE check) and if 1 = 1, the enemy and bullet are destroyed. If it is not equal the bullet simply passes through. I have a global attribute called Bullet.Type (1,2,3 etc) This is where the challenge starts....
Suppose,
Bullet.Type
Bronze bullet = 1
Silver bullet = 2
Gold bullet = 3
When I fire a gold bullet and then fire a silver bullet (1 trailing the other), when the gold bullet hits the werewolf, the actors die. This is because when the silver bullet (second fire) is shot, it changes the attribute of the gold bullet (at present 3) to silver = 2. How do I ensure that each bullet has its own bullet.type value such that fired bullets retain their bullet.type value.
Vice versa, when a silver bullet is fired and then followed by a gold bullet, the silver bullet does not kill the werewolf because now this time round, the bullet.type global attribute has changed to 3.
I know this has probably got to do with playing around with Constrain Attributes vs Change Attributes behavior but I am not able to get them to work properly. Or is there some other efficient way to sort this out? Can anyone guide me through this please?
Cheers!!
Comments
The first part you have is correct. Use a global integer attribute to spawn the correct bullet type.
For the second part, I would do something like this:
Create three separate bullet Actors (or however many you have)
On the Home Screen, make a new Tag called "Bullet", and drag these bullet actors into that tag.
In the Werewolf Actor, have the Rules set up something like this:
Rule
When all conditions are valid:
Actor receives event overlaps or collides with Actor with tag Bullet
-----Rule
-----When all conditions are valid:
-----Actor receives event overlaps or collides with Actor of type Silver_Bullet
----------Play Sound "werewolf_death.ogg"
----------Destroy
Hope this helps!
Joe
Thanks for your reply. The tag logic you have advised would definitely work if I were comparing different bullet actors (or tags) with the various enemies I have. But I actually have 9 different bullets. To reduce dependency on too many actors (to increase code efficiency - I hope), I am just having 1 bullet actor and not 9. This bullet actor's image and the global bullet.type attribute changes when I change the bullet.
So this is where I am stuck. Can I just have 1 bullet actor (which changes images and corresponding bullet.type value) and still simulate different bullets? Please advise.
Put a Change Attribute loose at the top of the behaviors for the bullet, like this:
Change Attribute
self.myType = game.bulletType
That SHOULD set the "myType" of each bullet when they are spawned.
I understand that Change Attribute happens only once unlike Constrain Attribute which keeps constantly updating.
I did that. Still what happens is that because game.bulletType is common to all the bullets being spawned, the moment the first bullet is followed by another and then another, it gets updated with the latest bullet.type attribute.
But let me try it again and see if it works. I might have made some logic mistake especially with many attributes and variables running around.
Nope it doesn't work. It is just as I explained. Unlike real coding where we can store the individual attributes in either class instances, arrays or pointers and allow individual actors to interact directly with one another, GS only allows interaction through global attributes. Therefore, when we modify the global attribute and then link it with actors, all of them get affected equally.
I really hope I am wrong in my understanding here because I really don't want to resolve this with multiple actors of the same type. I have a dozen different bullets with a dozen different villains not to mention different guns. Imagine the sheer number of actors that need to interact here.
There are three types of Attributes in GameSalad:
Global Attributes
Actor attributes
Scene Attributes
GameSalad uses the Prototype/Instance model, Attributes you place in the Prototype are in all of the Instances of that Prototype.
Instances CAN both listen to, and set, any attribute of ANY other Instance in the Scene. An Instance can also listen to and set (most of) the Scene Attributes, such as the Scene's Camera data. Prototypes CANNOT. You will need to click the padlock of an Instance to access the Scene Attributes.
Change Attribute only fires once.
Constrain Attribute constantly fires.
So you should have a global Attribute (integer) called bulletType. When you press the spacebar, and spawn a bullet, the bullet prototype should have an integer attribute as well, called something like "myType".
At the time of firing, set the myType of the bullet to the global bulletType. Use a change attribute behavior. myType will only be set once - it will not keep updating as the global bulletType changes. If you wanted to always have it updating, you would use Constrain Attribute.
So in the bullet Prototype in the Library, create an integer Attribute called myType. And put a Change Attribute at the top of the list with Change Attribute: self.myType To game.bulletType.
Again, that SHOULD work. Each bullet instance should have their own "myType" when they get fired. It shouldn't change as the global bulletType changes.
The Prototype/Instance model is sort of a dumbed-down version of Class/Instance model. It pretty much works the same way.
You still don't have access in GameSalad to Arrays (hopefully they will implement them soon!) or pointers, but this system can do pretty much everything else.
If you are still having trouble, please let us know!
Joe
I tried what you said. Now this is the outcome...
I have 3 actors in total for now.
Gun, Bullet, and Enemy
In the Gun Actor,
I have a behavior which checks for Keyboard input,
if 1 is pressed, then gun color changes to bronze,
if 2, silver,
if 3, gold
The gun has a Self.Mycolor attribute which is set to either 1,2, or 3
When I press space (shoot)
I assign the Turret's color (self.mycolor) to global bullet.color attribute using change attribute.
I then spawn the bullet (under Turret Actor)
In the Bullet Actor,
Under a Rule, at self.time = 0 (meaning when bullet's time is at 0), I initialize its self.bulletcolor to global bullet.color using change attribute.
Using a different rule, I test the self attribute against 1,2, or 3 to change the color/image of the bullet accordingly. Under this rule, I also change another attribute called game.collision.bullet to self.bulletcolor. This collision.bullet global variable is simply another variable to pass and compare with the enemy actor when they collide.
The Enemy receives the game.collision.bullet variable and assigns to its own bullet.color attribute. This is then checked to see if 1 = 1 or 2 = 2 or 3 = 3. If so, the enemy is killed.
However, the problem I have mentioned before seems to persist. What I have done is to create different display labels to test the values being passed around. I find that while the global variables seem to update correctly most of the time, the value (number) on the bullets are not. The first time I fire without changing bullet, the numbers show correctly, meaning number 1 is displayed on bronze bullet as it travels. But when I change gun to different color, say silver (which is 2), 5 bullets display 2 on them but the 6th bullet displays a 1 or vice versa. Basically, the bullet values are not getting updated correctly.
Example, first time game loads and I fire bronze...
it goes 1 1 1 1 1 1 1 1 1 etc
after I change gun, it goes 1 1 1 2 2 1 1 2 1 1 1 1 2 2 2 etc or 2 2 1 1 1 etc
Also if I fire a bronze bullet on a silver target, the target does not die. But if I fire a bronze bullet and immediately change gun and fire a silver bullet, when the bronze bullet touches the target, it dies.
Are you able to follow what I am saying here?
I really appreciate your time and help. Thanks.
That global attribute is going to keep changing every time you fire a new bullet.
Like you said though, it isn't easy for Instances to "talk" to one another. You CAN do it, but it is more for when the instances are manually placed in the Scene, not when they are spawned.
Unfortunately, the way GameSalad works, you are probably going to need a different Actor for each bullet, and a different Actor for each Enemy type.
It certainly is tedious, but it will work.
In my games, I am loading and saving around 200 Attributes, and some of my Rule sets are 300 Rules long! Without for loops and concatenation, things get ridiculous real fast!
This tediousness is countered by the absolute speed of getting your app running on a device. Knocking out an iPhone game in days or weeks is pretty amazing.
But yes, I feel your pain!
Hopefully as they keep working on the software, it will keep getting better!
Having multiple actors for bullets and enemies would certainly make things straightforward though tedious. Infact, I sort of have a prototype version which does that. My concern is the amount of resource that is going to be used. What is the maximum number of actors I can have at a particular frame or scene without slowing down the iphone or ipad? I have seen a couple of threads where members were discussing about avoiding frequent spawning and destroying as they would hog the computing resource. But so long as each actor spawned is destroyed without leaving any leak, it should not be a problem right?
As you may have guessed, this is a tower defense game I am trying to build. So imagine, different bullets, different enemies, number of each bullet fired and number of each enemy spawned, plus miscellaneous actors.
Thanks.
A Tower Defense game is a mighty challenge in GameSalad.
JGary made one a few months ago.
Not easy! All without Arrays, for loops, or proper functions.
The other thing to watch out for is the use of Constrain Attributes. They are real resource hogs,
especially on older devices. You should test your game with the GS Viewer as soon as possible.
That will show you the RAM usage as well as the FPS on the device.
In a typical tower defense game, the creeps would have health bars above them. In GS, you would create that with a Constrain Attribute ( to keep the health bar Constrained above the creep) But more than a few Constrains will kill the frame rate.
You'll also need Constrains to constantly get the distance between the towers and the creeps.
You will definitely need to be creative to pull it off!
I am now facing a new challenge...pathfinding. The creeps have to find their way to the end point through the maze. The maze I have now is basically a background image. Imagine a maze which spirals inwards (rectangularly..not circle). For now, I am hardcoding the various points (edges of the maze) the creeps move towards each nav point. Upon reaching it, they move towards the next point and so on till they reach the destination. So its something like, left to right, then top to bottom, then right to left and so on. So each nav point is hardcoded in the "Move To" behavior. Rules will check if the creep has reached it and if so where do they move to next.
Do you think there is a more efficient way of doing this?
6 of one, 1/2 dozen of the other...
I got my game to work. I only have one set of enemies and one set of bullet but seems to be working fine. I am using the hardcoded navigation points for pathfinding for now.
One hiccup though...I am trying to set a rule that when there are no creeps left, player life is more than 0, I display "you finished level 1". Number of player lives and no creeps left is initialized to 10 and 50 respectively.
Each time the creep reaches the destination, player life is reduced by 1. Creeps.Left is also reduced by 1.
Each time, a creep is killed, creeps.left is reduced again by 1.
But I notice that every time the number of creeps on screen is reduced to last 4, the game displays "you cleared level 1", which is weird. Is there a logic error in my game?
Just to confirm, in that Rule that checks all the conditions, that it is indeed set to "All" and not "Any"?
You seem like a competent programmer, so I am sure something is just being overlooked...
Its set to "All" only. I have been playing around with the logic a bit, but it keeps displaying level is finished when there are still 4 creeps remaining. Need to create display labels now to debug this. I will update you soon.
Well not really competent. Did some C programming during college but not since. I am actually enjoying GS. I got my basic tower defense already up in 2 days plus 1 with all the artwork. It would have taken a week if I were manually coding everything.
I am basically trying to spawn my creeps (global attribute MAX: 50) at certain intervals. In this case,
After 5 seconds into Game.Time (Game.Time >= 5),
Every 10 seconds,
For 2 seconds,
Every 0.2 seconds, spawn a creep
So what happens is for every creep stream, 9 creeps are spawned. Because of this logic, the total creeps spawned overflows to 54 instead of the maximum 50 I have set. Despite the Rule which checks numOfCreeps <= 50, then timer spawn, why does it overflow to 54?
I also noted that if the interval per creep is 0.2 seconds then in 2 seconds should there not be 10 creeps instead of 9?
However, I still don't get the second part..why 9 creeps and not 10 are spawned.
You're right, that should be 10, maybe that final one is getting chopped off?
The Timer isn't perfectly accurate, there might be some slippage, so maybe by the time it gets to the last one, the 2 seconds are already up...
A better way, instead of relying on a Timer, would be to use an integer as a "creep count" and increase it every time you spawn. That should lock it down a little better.
So:
In the spawning Actor, create a new integer attribute called 'creepCount'
And set the Rules like this:
Timer Every 10 seconds
-----Change Attribute: self.creepCount To: 0
-----Rule
-----When all conditions are valid:
-----self.creepCount < 10
----------Timer Every 0.2 seconds
---------------spawn a creep
---------------Change Attribute: self.creepCount To: self.creepCount + 1
I believe that should do it.
Again, if you plan on releasing this to the App Store, you should really test it on a device asap. On older devices, Timers and spawning can cause hiccups. You barely have any RAM to work with. And every time you spawn something it adds to the RAM. (which is why some people, instead of spawning/destroying, just move the Actors offscreen and reuse them....)
Using the Preview built into GameSalad is a little deceptive as you have all the RAM of the computer behind it. Plus the processor is much better. It's great for testing logic, but not performance.
What you're describing should work fine on an iPhone4, Ipad, and even 3GS, but older iPhones like the 3G and older iPod Touches will struggle...
Just a word of caution...
I got the GS Viewer after much effort. I tested my basic game on my iTouch. You are right...spawning does slow the frame rate quite a bit. It starts off @ 60fps and each time a creep is spawned, the fps drops and by the time all the creeps are in, its fluctuating at around 25-30 and that is without any of my bullets flying around which if spawned will slow down drastically.
Only step I have taken thus far is to reduce the image sizes which has helped a little and also reduce the total number of creeps spawned to 36 instead of 50. I did go through a couple of other forums which also mention the same thing about moving actors offscreen and onscreen. But I am unable to form the logic in my head. I have built my game based on spawn/destroy logic and am stuck on how to modify it. Do I have to pre-spawn or drag in 36 creeps and put them off screen and keep rotating them?
Either pre-spawn then at the beginning of the level, or place them there manually.
When they die, or reach the target, move them back to the beginning.
Straightforward and tedious!