- Home /
Bonus points tile! Need help!
Ok, guys, Im making a simple board game with a tile system. I want to make some of these tiles give the user some bonus points to the score, when passed over (only the first time the user passes over it).
I have no problem, making a single tile of this type, and it works perfectly for ONLY ONE tile. But I am really confused and need to know how to make this work for more than one tile of the same type, in the same script.
Right now I am doing this
//this is called every update frame
if(Physics.Raycast(transform.position,Vector3.down,out tilechecker))
{
//tile is a 'quad' which is place ontop of the actual tile (basically just a texture)
tile = tilechecker.collider.gameObject;
if(tile.tag=="bonus tile" && !collectedbonus)
{
//tile2 is the actual tile on which the quad named 'tile' lies
tile2 = tile.transform.parent;
print ("got bonus");
points++;
collectedbonus = true;
}
}
I have a general idea that I have to use some sort of arrays, but really don't know how to implement it. The way my script works is, the player has a ray coming out of the bottom of it, checking for the tile every update frame. On hitting the desired tile, the bonus gets added.
Answer by Hoeloe · Sep 04, 2013 at 11:06 AM
The problem is that you're using a boolean flag, collectedbonus
for all tiles. The issue occurs because after you collect one bonus, that flag is set, and so when you come to the next one, the code finds you have already collected the bonus, and so it doesn't give you any more. You can solve this in several ways.
The simplest way is to add a script to the bonus tile, which contains the boolean flag. Then, in your collision script, you can use GetComponent
to access this script and read and set the flag. That way, each tile has their own boolean, and it will work correctly.
Another solution, though messier and less efficient, but will work if you are for some reason unable to add scripts to individual tiles, is to forgo booleans entirely, and create a Set
of bonus tile objects. Initially, this will be empty. Whenever you cross over a bonus tile, you can check if it is already in the set, and if it is, then it has already been touched. If it isn't in the set, you can add it in, and give the player the bonus points.
There are other solutions, but those are the two most obvious ones.
Could you please explain the 2nd example more thoroughly? Possibly with an example code
I understood the first method, I'll try that. Will the code for method one look something like this? //tile.cs
if(check == false)
{
check = true;
points ++;
}
//player.cs
//check collision with tile
tile.GetComponent<tile.cs>
??
No. You rarely ever need to use the ".cs" extension in code. The generics will just refer to the class name, not the filename. You'll need something like this:
Tile t = tile.GetComponent<Tile>();
if(!t.check)
{
check = true;
points ++;
}
You might want to have another look over some of the basics of C# and Object Oriented Program$$anonymous$$g, because this is fairly trivial stuff, and if you plan on making anything at all complex, you'll need this sort of thing to be second nature.
The 2nd example is a little more complex. Basically, it keeps a list of all the bonus tiles that you've already passed through. Every time you touch a bonus tile, if you've already been through it, it will be in that list. If it's not in that list, then you haven't already been through it, and you can add the score and add it to the list.
Thanks a lot! Tried out your first method, works awesome, but am going to implement OtsegoDoom's as it fits me better for now
Hey Hoeloe, I actually didn't get your first method. Thought it worked for me but I think I messed it up.
Could you just write the script down for me. Like what exactly am I supposed to write in the Tile file, and what in my player file
Simply? No. I could write it down for you, but I won't, because this is a very simple problem, and that way you're not learning - I suggest you take a look at some basics of object oriented program$$anonymous$$g, as once you get to grip with that, you'll understand what I'm talking about, and it will help you in the long run to develop your game.
Answer by OtsegoDoom · Sep 04, 2013 at 12:54 PM
If you want to do everything with one script you can simply change the tag of the object the first time it's hit. Once you change the tag on the tile, that specific tile will never trigger the bonus again.
if(tile.tag=="bonus tile")
{
tile.tag = "UsedBonusTile";
//tile2 is the actual tile on which the quad named 'tile' lies
tile2 = tile.transform.parent;
print ("got bonus");
points++;
collectedbonus = true;
}
In the example above the tile once triggered will change the tag from whatever it currently is to "UsedBonusTile". Then if another collider interacts with that tile, your script will just ignore it since it doesn't have the tag it's looking for. I also modified the If statement, because the boolean is no longer necessary.
That is another solution. Just be careful, because it could break other parts of the code that make use of the tag, if there are any.
Of course. Without seeing the rest of the code it's hard to say what (if any) issues changing the tag may cause. :)
Certainly. Just thought it was worth pointing out to Puneet$$anonymous$$ that it may cause problems.
Thanks for this answer! This was the easiest solution for me, as I do not wish to use bonus anywhere else for now. If so, I will definitely go for Hoeloe's 1st method, as it works equally fine (but for now I'm trying to keep all my script into one file, since that's what I've been doing all this while)
Answer by RyanZimmerman87 · Sep 07, 2013 at 11:52 PM
OK I'll try to give an example of how I would handle this:
//PlayerScript
//create variable to hold the current tile object
public gameObject rayHitObject;
//do all stuff to determine if you hit bonus tile
//Added range to your raycast make sure it goes far enough
//just to be safe, did not see that in your code yet
if(Physics.Raycast(transform.position,Vector3.down,out tilechecker, 200))
{
//you should only do this once per move
//do this once per tile
//it looked like you might do this every FixedUpdate()
//in another thread of yours I think you should fix that
//obtain your current tile Object from your raycast
rayHitObject = tilechecker.collider.gameObject;
//I don't know why you have a Script for just the bonus tiles.
//You could and probably should have one script that can handle ALL the tiles
//if your tile script is named bonus after you get the rayHitObject from the single Raycast
//you can go:
//prepare to handle this one object one time (not every Fixed Update)
//Grab the tile Script Component to change Bool:
bonus otherObjectsScriptBonus = rayHitObject.GetComponent<bonus>;
//set bool
if (otherObjectsScriptBonus.check == false)
{
otherObjectsScriptBonus.check = true;
//call a function to update your points only once
}
else if (otherObjectsScriptBonus.check == true)
{
//wait for the next time they move to cast another ray...
return;
}
}
Hopefully that helps it seems like you are very close but the problem of correctly setting a bool on an object only one time is extremely simple if you do it like this example. You just need to make sure you only do it once per move and control all your logic. In another one of your threads it looks like you were trying to call all kinds of stuff every FixedUpdate.
I would recommend only doing the minimum work required for both performance and so you can solve this easier. So do one rayCast per move, handle the logic, and then once the logic is complete allow the player to move.
$$anonymous$$y tile script handles all the tiles, but only have posted the bonus one here, since the others are pretty much working fine.
Yes, I have editted my logic a bit to do $$anonymous$$imum things per fixed update. I'm checking the tile every fixed update, as I'm not sure if it would work in any other place.
Could you explain your bonus checking script a bit more? I didn't understand why I should check it the check it true, and what I am supposed to do there? Return what?
Technically checking the tile every fixed update should be fine, but your logic will have to be flawless. It might easier to ensure this by only doing the logic once per tile, and could boost performance but it's not necessary.
Every time you land on a tile you can check to see if it's a bonus tile, if you already landed on it (when it's false) then you get the bonus points. When it sets it to true it also updates your points.
Then whenever you land on it again it is already true so you won't be able to get points again, you would just treat it like a normal tile.
So you can use the bool conditions to deter$$anonymous$$e whether you landed on a tile or not. And you can also set up a variable maybe called tileTypeInt for what type of tile it is.
So every time you move the player you can do a check of what type of tile it is, and then a bool for whether you landed on it or not yet, or a counter for how many times you landed on it etc.
I didn't understand the difference between what I'm currently doing and what you said. I don't believe I require to keep track of how many times I've hit that tile, since I only need it once. But if there is some other reason for counting, let me know
Yeah you don't need to that's just another example of ways to keep track of all the logic. Did you get this working now? It seems like you are so close!
From what I feel, I have done everything correctly, I just don't know why Unity is giving issues for it. The logic is correct and it works prefectly for 1 tile. $$anonymous$$aybe it is an issue with my ray hitting it?
I just noticed that my player moves down 0.02 units down the Y plane (into the board) as soon as the game starts. Could that be the reason for faulty detection of tiles?
Answer by PuneetK · Sep 11, 2013 at 08:38 PM
Fixed this issue, was a problem with the way I was calling the other script! Thanks!
This thread been going a while. I think its time to click some thumbs up, Puneet$$anonymous$$ :P Show your appreciation with karma.