#ABBs spaghetti code hour
1 messages Β· Page 1 of 1 (latest)
Right, so, I'm still on this damn box drawing problem
At the moment, my code is back to only drawing one box over one target when it should be drawing three
might as well break er down from A
Yep
Going to just share ALL the debug info here
To start off with, let me paste the code real quick
iirc this is the targeting reticles?
I may have to go unexpectedly, warning π
So here's the situation. Got three targets I'm testing on, and the program sends debug logs whenever a target is marked as already boxed
Here's the problem with that debug log
It's marking those other two as already boxed as well
But that's not all
When I first acquire all those targets, the box jumps from one target to another like so:
Now, I know part of what's happening. The box goes to one, the program says "Hey, one already has a box" and moves on with the others
What I don't get is that I never actually specified that a box should be deactivated or moved to an inactive list if a target is alrteady boxed
I only ever specified that a new box should be pulled if a target doesn't have a box
And at the moment that's not what's happening
Now, the inspector is showing that there are three active boxes
I guess they're all in the same spot
I don't know how to tell for sure though
So, you know me, I wouldn't come here and ask for help if I weren't already completely at a loss
That's about the crux of the problem
could be a problem with the candidate references? maybe all the boxes are trying to pile onto candidate 1
They shouldn't be piling onto candidates, only targets, but that does still stand. Let me try making that a forr loop
could also be a dumb logic thing, it's getting to a pretty confusing state π
I seem to have a fantastic capacity for coding myself into the dumbest fucking holes ever
debugs in all the conditionals might shed some light
I didn't start unity from a programming background, so all my techniques are.. pretty much as simple as possible - I see this all the time though, overcomplicated solutions π
not worth junking at this point, imo it shoooould work how youve done it
just.. slightly unintended behavior π
better than compiler errors π
Well that didn't do it
Now it's not doing the "jumping from 1, to 2, to 3" thing
New code
New logs
new inspector
And as usual, I am half a second from smashing my desktop in with my fist
To figure out where all the boxes are, pause the game and focus on each of the boxes in the scene view.
Oh for fuck's sake
They all redirect to "TargetAvailable" in the canvas
Not the clones
Just that one TargetAvailable
aha
It isn't even USING the clones I made despite me specifically telling it to
so it was a target misreference π
Right, but I'm specifically telling it to use ones from the inactive list
It's not doing that of course, because that'd make too much fucking sense
let me try removing the original prefab from the heirarchy
I guess that's the issue(line 43):
Instantiate(greenbox, holdingtank);
greenbox.SetActive(false);
inactiveboxes.Add(greenbox);
runcandidatecheck--;
You add the greenbox(prefab?) to the inactiveboxes list.
oh great, now it's jus tdoing nothing
so all of the elements in inactiveboxes are a reference to the prefab
Right, let me give THAT a shot
give what a shot..?
instantiating greenbox prefab to the inactiveboxes list
I gotta figure out which of the 11 overloads that is for Instantiate real quick
You should read what instantiate does and specifically what it returns.
I know what it does, and what it does is not what I need it to do
Right, any way to spawn in from a prefab of something that isn't already in the heirarchy?
The whole thing
Wdym? I think you still don't understand what it does.
yep, easily enough
if it were me that'd be like, my entire solution for this system lol
Well then clearly I don't, and the API isn't helping
Let's go over that code in your if statement starting from line 43. What do you think it does?
What's the magic nuance this time?
Line 43...
it makes a new greenbox and moves it to a transform I have offscreen
It doesn't actually move it into the list
I know that
Line 44
let me guess, it's not deactivating the greenbox I just spawned but the gameobject that's actually in the heirarchy because fuck making sense?
It does deactivate the "greenbox". The question is what is the "greenbox"?
Judging by the way things are going, not the one I just instantiated in
Which is the one I actually care about
Exactly.
I think the magic nuance issssss
instantiate returns a reference to what it instantiates
and you need that instead
Right, any way to actually refer to the object I just instantiated?
yesr indeedy
Now look at the Instantiate docs page. Read the first line of the description
I assume, you understand what "returns" means, right?
Fuck it, let's just assume I don't at this point
declare an empty gameobject, and define it using the instantiation, like objectRef = instantiate(clone, blabala)
or.. declare and define it all in one line?
idk theres probably a cooler way to do it.
Okay, then I'd suggest going over the C# basics. Specifically about functions and what return keyword does.
tbh I actually think that may be a different use of the term return?
confusing..
might be related and I just don't grasp the significance
Honestly, I don't even know how to approach educating about something like this. It's just something so basic that there's no specific way of describing it.π€
Okay
When you do GetComponent, what do you have on the left side?
so I've got a public GameObject tempragref;, and then when I instantiate, I go tempragref = Instantiate<GameObject>(looselimbsragdollprefab, playerprefab.transform);
and then tempragref is a reference to that instantiation
In math if you do x = 2 + y you have a function 2+ y, right? And you want to get a result of the function. How do you get that result? By assigning it to a variable on the left side.
Function 2 + y "returns" a result.
looselimbsragdollprefab btw, is a prefab not in the heirarchy, dragged in with direct public reference from assets/prefabs/
Yeah, it's the code's "answer" to your question, or end product to your parameters
Let me guess tho
"Except when it isn't"
Right?
Don't even worry about it, I just implemented Uthel's advice of instantiating the gameobject in a new gameobject and I'm now actually closer to fixing the problem.
In programming we say that a function "returns" a value.
yeah. And Instantiate returns a value of a clone. But it didn't change the value of "greenbox", I get it
Okay?
I get it.
in my implementation, I leave tempragref null, since I won't be using it until after its been spawned and set
that way I don't actually need an object for it, it just sits empty
Right
Now
It's actually spawning three boxes in the inactive list, and moving them into activeboxes as needed, which is good
That's a half step forward which is about as much as I've ever managed to get with this dumbshit problem
New problem
All the boxes are going to only one target. Again.
let me paste the new code and stuff
that sounds to me like perhaps candidates arent getting applied to targets properly
Yeah, I know that's what it is
ahhh dunno, hard to say
But I have no godly idea why
Well, I do have an idea why
It's reading that the target already has a box around it and doing nothing about it
Same thing happened when I used a forr loop for this instead
sounds like a reasonable course of inquiry- i gtg tho gl
This debug would get printed any frame that onscreen is true, so I don't think it's a reliable debug method.
Yeah, but the point is that it's still not actually taking the fact that the box is already there and using it as a hint to move on to the next item in the targetlist
I'm going to try a forr loop for this and see if that does anything
Where do you move it to the next target?
Ah, I see
I don't specify it, my hope was that it'd take "alreadyboxed" as a hint not to box that one, and instead box the next thing in the list. Which was clearly an error on my part, assuming that computers would do reasonable things.
I'll try a new strategy for this for tomorrow. Just make some function that goes down every target in that list and draws a box around it with no smart shit to try and see if that target is already boxed.
Literally, "go to item 1 on the list, put the box on the target, move to item 2 on the list, do the same thing, move to item 3 on the list, do the same thing, until you're at the end of the list"
Computers always do reasonable things. It's our instructions as programmers that can be unreasonable.π
I thought "for each item in targetlist, if it's already boxed, don't bother boxing it" was pretty fucking reasonable
For perfectly logical machines they sure don't make sense
I think the problem is that your alreadyboxed state is defined inside the loop. It would be much clearer if you had a Box object that could have this state instead.
Your alreadyboxed state is not linked directly to the items in the list. That's the problem.
To the items in the targetlist or the box list?
Because I would imagine it's tied to the targetlist, given the fact that it is tied to the target list
So, what are you saying? Have some boolean attached to the box that determines if that box already has a target?
Because I don't imagine that'd solve the problem either
Do I have to put something in the code that specifies "if a target already has a box, don't fuck with the box the target already has and leave it be?"
Here's a simplified algorithm of what you want to do. Correct me if I'm getting it wrong.
foreach(target)
{
if(target is not boxed but within the screen)
{
var box = GetABoxFromPool();
ApplyBoxToTarget(box, target);
}
else if(target is boxed but outside of the screen)
{
var box = GetAppliedBox(target);
PoolBox(box);
}
}
not really
Also I thought Csharp doesn't have "else if" statements
Actually, wait, no this isn't it
of course it does.
What I want it to do is this:
foreach (target in targetlist){
if (target is onscreen and doesnt already have a box){
giveitabox();
tie that box to the targets transform
move to the next target in targetlist;
}
if (target already has a box){
dont give it another goddamn box and move on to the next target in the list();
dont fuck about with the box it already has, leave it be for god's sake();
}
}
It's struggling with that second part
It can recognize that the target already has a box
It just does nothing with that information, gives the target a second box anyway (sometimes, sometimes it just moves all three boxes to the last target in the targetlist), and repeats this cycle
I think the main problem is the return on line 107. It returns right after the first target, so it just doesn't go to the next targets.
But there a bigger overall problem with your code
it's convoluted
hard to read and debug.
One thing at a time here, okay? Would "Continue" make it move onto the next target?
Here's how you can rewrite your code in a more readable fashion:
//A separate script/class
public class Target
{
public GameObject Box { get; set;}
public bool OnScreen { get ; set;}
public void AssignBox(Gameobject box)
{
Box = box;
//Set parent and position of the box, etc...
}
}
//in your update method
foreach(target)
{
if(target.OnScreen && target.Box == null)
target.AssignBox(GetABoxFromPool());
else if(target.Box != null && !target.OnScreen)
PoolBox(target.Box);
}
yes.
Okay
8 lines vs 32 in your code.
Of course, you'll need to define the new class and some new methods, but the algorithm itself would be crystal clear
Okay, but once I add all the code in here that manages the object pooling for the box and determines all the lists and where the targetlist is coming from (a separate script), it's not going to be eight lines is it?
No, It will still be less then your code though(if you exclude the braces).
So, let me just go through this revision line by line here
I already get the box gameobject,
I already declare a bool for whether or not an object is on screen
I already have a script to assign boxes
and I already have a script to assign boxes (the only part of this script that isn't working properly)
I will admit, there is some extraneous shit in there that I plan on removing once this thing actually works the way I want it to, but it sounds like this code would be just as complicated by the time I'm done defining and writing what all those shortened methods mean
If the problem is getting the targetlist, that's in a different script
Not really. The way you get the boxes and check if a target already have one is messed up. It's hard to follow and debug because it's all mushed up in one place. With things separate in each method, you can debug the return value of the method or some of it's work and see clearly what's going on. Programming is abstraction. The more abstract your code is the better.
I'm gonna keep it 100 with you chief, I fucking give up for the night.
I'll figure this shit out tomorrow
Last thing I'll say is, I don't have the time to get a fucking PhD in programming, I was a history major in college, I'm fucking stupid, okay? I'm not trying to do this for a living, I'm just cramming all this into the few hours of free time I have in a day
My metric for success is just the shit I make working
tbh im surprised you'd take this approach at all without a background in programming - you'd probably be able to easily get away with just having inactive already placed child boxes on the enemy prefabs, and enable disable it on a simple distance to player check
no pooling no lists, super simple
You don't need a PhD in programming, but you need a will to learn and improve. Many people on this server put a lot of time and effort into gamedev/programming. If I see someone that says something like "man, I'm just doing it for fun, I don't wanna learn anything, just give me the complete code", I'm getting really annoyed and discouraged from helping them.
If you want to "make shit working" then you've got to put effort into learning. If you don't, then maybe gamedev is not a suitable hobby.
I'm fine with learning shit, I think I've been pretty goddamn careful about not asking for complete code, and I usually go to the API and tutorials unless I'm just really at a dead end
But when I'm at that dead end and I have to go through a wall of "are you actually fucking stupid, get fucked," yeah, it's not exactly helpful.
I'll rewrite the code to make it more abstract
Well, I've never said any of this. I said that you have a problem with code structure and gave you an example of how you can fix it.
You said "you should learn what return means" phrased as 'you should learn the basics" when the problem was actually "I don't think that word is referring to what you think it's referring to"
One is a lack of effort on my part and the other is just me not catching that something didn't mean what I think it meant
FINALLY
This was the problem code after fixing
if (alreadyboxed == false && onscreen == true && i <= boxpool.Count && i >= 0)
{
GameObject box = boxpool[i];
box.transform.position = screenposition;
}
this was the problem code before fixing
if (alreadyboxed == false && onscreen == true)
{
foreach (GameObject box in activeboxes)
{
box.SetActive(true);
box.transform.position = screenposition;
alreadyboxed = true;
}
}
The problem was, I wasn't specifying which box in the box list to draw on
I was just saying "iunno pick a fuckin' box shiiiii"
And that's what it did
as dlich says, the computer was acting entirely within reason, doing exactly what you told it π
Sounds normal
I'm never going to be done with this
I'm going to spend the rest of this project focused on drawing fucking boxes.
I mean, if you want.
you are in charge π
you will be hard pressed to find someone who cares -how- the boxes are handled π
The players, who need this UI to work so they can understand what they can actually lock onto with missiles
yeah, but how? the method doesn't matter
none of them care how
is what I meant π
I can't think of any other way how that makes sense
I can't tie the box to the target because the box has to be in the UI canvas
I can't just instantiate a new box and destroy it at will becasue that'd be too costly
Anyway, the new problem is that it's not actually drawing a box on any target unless the last item in the targetlist is in frame with it
I know it's because of all the Forr loops somehow, and I'm so fucking through with this
I'm sitting here maniacally laughing at how fucking futile this whole effort is, and it's 11 PM
and see I'd tie it to the target and don't think instantiating/destroying would be too much, and if in testing, it proved to be, I'd switch to always having the quads on the ships, and enable/disable
doesn't need to be on ui canvas
As I said previously. There's a systematic problem with your code architecture. You're gonna keep on stumbling on issues, unless you rewrite it.
But yeah, what Uthel suggests is way simpler to implement.
I'd add a script to orient the quads to the camera so they look like dynamic ui elements scaling with the ships, and animate them popping in and out
and I can almost guarantee it'd not be obese
animate with the overweight animator mind you, not using efficient lerps
public void Update()
{
getcandidates(); //get the list
listmanage(activeboxes, inactiveboxes, targetlist); //detect changes in the list
targetmanage(targetlist, activeboxes); //get boxes for the targets in the list
}
I did what you asked
I put everything in a neat little function outside the update function
getcandidates(); //get the list
Get the list of what?
break time for sanity's sake
What do you have in these methods? If you just placed whatever you had into a method, nothing changed at all
I can read my own code just fine, the problem is, every time I account for a new edge case and fix it, a new, different edge case comes up
How many goddamn methods will I have to break this code into?
Does EVERY if statement have to be its own method?
The problem is not just putting code in a method
Share your code. I can't say anything specific without seeing how you implemented it.
Ok, so nothing changed at all.
There's literally 0 point in putting that code in the methods.
The same code that you had before.
Fine. Delete the code? Start over a third time?
I'll do it! I do not care at this point!
You don't even need to restart from scratch. Only refactor.
That's the thing. You made it too complicated. You need to simplify it.
For starters, listtransfer doesn't make sense. You want to move the boxes between active and inactive lists, but you just move the top element in the list regardless of whether it's the element that you really need.
And pray tell, how does that happen?
Is it amounttomove?
Because I have no clue how else to specify that I only want this to happen once, and not on every frame
Because that was the problem I was getting last time, when I tried to do it simply
I tried making this simple, and then I had to include a fix for the simplicity, and then a fix for the fix, and a fix for the fix for the fix
Instead, you could have something like this:
private void SetBoxActive(GameObject box, bool active)
{
box.SetActive(active);
if(active)
{
activeList.Add(box);
inactiveList.Remove(box);
}
else
{
activeList.Remove(box);
inactiveList.Add(box);
}
Fucking, setactive can be used like that?
Why not? You pass it a bool. Of course it can.
I fucking tried using it as a bool earlier and it didn't work
I guess I used it as a bool but not in the right way
Alright, making that change
Wait, hold on, why would I want to remove the already active box from the active box list?
If I'm setting the box to active, I want it in the active box list
Or rather, if it's in the active box list, I want it active
This code takes something set to active and removes it from the active box list
Yeah, you want to switch them around
Wait, also, how does this account for the fact that I'm moving things between lists?
There's no function here to make sure that I'm actually removing just one thing from one spot and putting it on the same spot in the other list
This is just going to lead to the same problem I had earlier before I added all these forr loops where the lists would end up not actually reflecting what they were supposed to reflect, and I'll end up with a ton of errors for being outside the list parameters
The place in the list doesn't matter. What matters is what object you get from the list.
That's what I thought too until I got countless ArgumentOutOfRangeExceptions or some other thing I'm probably forgetting the name of
But I'll do it
How is that code going to work here? How is it going to know how many boxes to transfer over if there's no parameter for that in the setboxactive method?
Actually, wait, that's not going to matter at all in the listmanager because the parameters required to make that block work don't even exist in listmanager
Which calls listtransfer the most
Would I have to put another forr loop inside the listmanage function at every if statement?
Well, I implemented the change in whatever snippet of the code I could before the thing fully broke. It kind of does what I wanted it to do now, but boxes linger on the screen long after targets have left and there's so many errors the framerate drops
I don't care anymore. It's midnight, I've run out of spite to keep myself up.
Well, that's enough spite to keep me up an hour longer I guess
Donno why I'm doing this, but that's all you really need for it to work. No extra methods(aside from the bool check), no additional classes. Super simple.
private List<GameObject> inactiveBoxes = new List<GameObject>();
private List<GameObject> targets = new List<GameObject>();
private List<GameObject> activeBoxes = new List<GameObject>();
private List<GameObject> boxTargets = new List<GameObject>();
private void Update()
{
for (int i = targets.Count; i >= 0; i--)
{
var target = targets[i];
Vector3 worldPos = target.transform.position;
Vector3 screenPosition = maincam.WorldToScreenPoint(worldPos);
if(!boxTargets.Contains(target) && InView(worldPos))
{
var box = inactiveBoxes[0];
box.SetActive(true);
box.transform.position = screenPosition;
inactiveBoxes.Remove(box);
activeBoxes.Add(box);
boxTargets.Add(target);
}
else if(boxTargets.Contains(target) && !InView(worldPos))
{
var index = boxTargets.IndexOf(target);
var box = activeBoxes[index];
box.SetActive(false);
activeBoxes.RemoveAt(index);
boxTargets.RemoveAt(index);
}
}
for (int i = 0; i < boxTargets.Count; i++)
{
GameObject box = activeBoxes[i];
GameObject target = boxTargets[i];
Vector3 worldPos = target.transform.position;
Vector3 screenPosition = maincam.WorldToScreenPoint(worldPos);
if (InView(worldPos))
box.transform.position = screenPosition;
}
}
Of course, you need to fill the inactive boxes and targets list on start.
I am very tempted to use that
At the very least read it and see what and how it does it?
The InView method is missing:
private bool InView(Vector3 worldPos)
{
Vector3 viewPos = maincam.WorldToViewportPoint(worldPos);
return viewPos.x >= 0 && viewPos.x <= 1 && viewPos.y >= 0 && viewPos.y <= 1 && viewPos.z > 0;
}
I'll be honest, I don't know if it'd work, I'm fully convinced that it'd at least work more than what I have now, but I kind of don't want to use it out of principle at this point
Not telling you to use it. Just to read and try understand the logic. Then compare to the logic in your code.
a stupid question from me, I might as well learn something here too - for the return in this Inview - I dont understand how its structured like an if - are those conditionals for when it returns?
I didn't even know indexof was a function
What if expression takes is basically a bool.
viewPos.x >= 0 && viewPos.x <= 1 && viewPos.y >= 0 && viewPos.y <= 1 && viewPos.z > 0 - This is just a big bool composed of several smaller bools.
Imagine defining each of them as bool x = viewPos.x >= 0
ohhhhh
then doing return x && y && z && w
It's midnight. Here's what I'm going to do
I'm going to delete the code I have because it's worth nothing to me
too late
I'm going to look at the code dlich posted and see what functions are in there that could help me that I didn't even know existed
I can already see a few
And then I'm going to write my own code again, because I specifically set out not to be the guy who asks for completed code.
good plan π