I'm working in Eclipse and I want to know if I can make an if statement that checks to see if the BufferedImage has been painted/drawn onto the frame. For some reason, it's not painting the correct image because clickable regions are appearing on that picture when they are not supposed to.
For example, when I click the region to go from 4>5 everything is good. When I click from 5 to go to 4 I end up at 6 because the 'regions' from 4 are appearing in 5 (The image should always be painted before the clickable regions are shown) before it's even being painted. I want to restrict this to check if the image has been painted onto the frame first.
I really don't want to use anything else besides what I have right now (so no new classes being implemented to do this task), I really just want a simple yet effective way to resolve this. Here is what I'm talking about:
...
MouseAdapter mouseHandler = new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
repaint();
if(n==0)
{
if(e.getX()>=459 && e.getX()<491 && e.getY()>=111 && e.getY()<133
{
n = 4;
}
return;
}
if(n==5)
{
if(...)
{
n = 4;
}
return();
}
if(n==6)
{
if(...)
{
n = 5;
}
if(...)
{
n = 0;
}
if(...)
{
n = 6;
}
return();
}
}
...
I think you might need to give a little more information. The problem might lie in how you repaint, not whether it was painted.
If you are running another thread as your main program, you might instead want to send the mouse events synchronously to that so that the main thread can process the mouse click and then repaint.
Another solution might be to override the repaint method and paint the buffered images there, but you may have done that.
Also, a little off topic, I noticed that you used for loops to determine if the mouse was clicked in a specific area.
You could shorten the code:
for(int i=459; i<491; i++){
if(e.getX()==i){
for(int j=111; j<133; j++){
if(e.getY()==j){
//action taken
}
}
}
}
To:
if(e.getX()>=459 && e.getX()<491 && e.getY()>=111 && e.getY()<133{
//action taken
}
This would take up less space in your code and less time checking every pixel.
Back to your question.
I dont know of a function to tell if a buffered image has been painted. The ploblem that you are having though might of might not be in the code provided. Posting the rest of your code would be beneficial.
Okay I found the solution, I forgot to come back to this question and let you know. The problem was that the mouse was double clicking for some reason. You could almost say it was 'recursive'. I decided to move the mouseListener from inside the paintComponent to outside of it, and surely enough that fixed it.
Related
I wanted my UI to not resize when user is still resizing the game (holding click in the window border) and only when the user has released the mouse the resize event will trigger.
I have tried to achieve it on Unity but so far I only able to detect windows size change, which my script checked every 0.5 second and if detected change it will resize the UI. But of course resizing everything caused a heavy lag, so resizing every 0.5 second is not a good option but resizing every 1 second is not a good idea either because 1 second is considered too long.
The question might be too broad but I have specified the problem as small as possible, how do I detect if user is still resizing the window? And how do I detect if user has stopped resizing the window (stop holding click at window border)?
You can't tell when someone stops dragging a window, unless you want to code a low level solution for ever desktop environment and every operating system.
Here's what worked for me with any MonoBehavior class, using the OnRectTransformDimensionsChange event:
public class StackOverflow : MonoBehaviour
{
private const float TimeBetweenScreenChangeCalculations = 0.5f;
private float _lastScreenChangeCalculationTime = 0;
private void Awake()
{
_lastScreenChangeCalculationTime = Time.time;
}
private void OnRectTransformDimensionsChange()
{
if (Time.time - _lastScreenChangeCalculationTime < TimeBetweenScreenChangeCalculations)
return;
_lastScreenChangeCalculationTime = Time.time;
Debug.Log($"Window dimensions changed to {Screen.width}x{Screen.height}");
}
}
I have some good news - sort of.
When the user resizes the window on Mac or PC,
Unity will AUTOMATICALLY re-layout everything.
BUT in fact ONLY when the user is "finished" resizing the Mac/PC window.
I believe that is what the OP is asking for - so the good news, what the OP is asking for is quite automatic.
However. A huge problem in Unity is Unity does not smoothly resize elements as the user is dragging the mouse to expand the Mac/PC window.
I have never found a solution to that problem. (A poor solution often mentioned is to check the size of the window every frame; that seems to be about the only approach.)
Again interestingly, what the OP mentions
" ..and if window has stopped resizing .."
is automatically done in Unity; in fact do nothing to achieve that.
I needed something like this for re generating a line chart, but as it has too many elements, it would be heavy to do it on every update, so I came up with this, which for me worked well:
public class ToRunOnResize : MonoBehaviour
{
private float screenWidth;
private bool screenStartedResizing = false;
private int updateCounter = 0;
private int numberOfUpdatesToRunXFunction = 15; // The number of frames you want your function to run after, (usually 60 per second, so 15 would be .25 seconds)
void Start()
{
screenWidth = Screen.width; // Identifies the screen width
}
private void Update()
{
if (Screen.width != screenWidth) // This will be run and repeated while you resize your screen
{
updateCounter = 0; // This will set 0 on every update, so the counter is reset until you release the resizing.
screenStartedResizing = true; // This lets the application know when to start counting the # of updates after you stopped resizing.
screenWidth = Screen.width;
}
if (screenStartedResizing)
{
updateCounter += 1; // This will count the updates until it gets to the numberOfUpdatesToRunXFunction
}
if (updateCounter == numberOfUpdatesToRunXFunction && screenStartedResizing)
{ // Finally we make the counter stop and run the code, in my case I use it for re-rendering a line chart.
screenStartedResizing = false;
// my re-rendering code...
// my re-rendering code...
}
}
}
I have bunifutransition1 that slides my mainpanel from left to right upon clicking showbutton. (It shows the hidden mainpanel.)
What I want is, when I click closebutton, the mainpanel will slide from right to left (to hide the mainpanel again). It seems that bunifuTransition does not have an animation that reverses the animation of VertSlide or HorizSlide.
What should I do to slide my mainpanel from right to left to hide it again on my form?
I was having the exact same issue but upon reading your question the answer finally became prevalent in my mind. The solution here is to stop using BunifuTranisition altogether and go for the good ol' for loops and the other mods, puns intended.
int originalWidth = panel.width;
int menuClicksIndex = 0;
private void beginTransition()
{
if (menuClickIndex % 2 == 0)
{
//This executes on the first click
for(int i = originalWidth-1; i>=0; i--)
{
// Loops from original width to 0
panel.Width = i;
}
}
else
{
for (int i = 0; i <= originalWidth; i++)
{
panel.Width = i;
}
}
menuClickIndex++;
}
This works for me but it glitches on the way back from left to right. So a mixed version with BunifuTransitions for the opener and the for loop for the closer would be the ideal solution here.
UPDATE 1: It seems as if while changing the width of the panel from 0 to say, 350, the content inside the panel doesn't render until the height is set to the max, but while decreasing the height from 350 to 0, the content is already rendered and so it seems smooth to close but cluttery to open, hence probably explaining why BunifuTransition is unable to do that as well.
Solution Here.
Just go bunifu transition properties
Open or dragdown DefaultAnimation. Find this option in menu ("Side Coeff") It Show value of
X and Y {X=1, Y=0} . You just change this value {X=-1, Y=0}.
Then Start your project and check. Your slider sliding left to right. :)
Keep enjoy.
Regards,
Haris Ali
Use this command: bunifuTransition1.HideSync(guna2Panel1); before any code on event button click!
I have the following pseudo code to clarify my problem and a solution. My original posting and detailed results are on Stack Overflow at: Wait() & Sleep() Not Working As Thought.
public class PixelArtSlideShow { // called with click of Menu item.
create List<File> of each selected pixelArtFile
for (File pixelArtFile : List<File>) {
call displayFiles(pixelArtFile);
TimeUnits.SECONDS.sleep(5); }
}
public static void displayFiles(File pixelArtFile) {
for (loop array rows)
for (loop array columns)
read-in sRGB for each pixel - Circle Object
window.setTitle(....)
}
// when above code is used to Open a pixelArtFile, it will appear instantly in a 32 x 64 array
PROBLEM: As detailed extensively on the other post. Each pixelArtFile will display the setTitle() correctly and pause for about 5 secs but the Circle’s will not change to the assigned color except for the last file, after the 5 secs have passed. It's like all the code in the TimeUnits.SECONDS.sleep(5); are skipped EXCEPT the window.setTitle(...)?
My understanding is the TimeUnits.SECONDS.sleep(5); interrupts the UI Thread uncontrollable and I guess must somehow be isolated to allow the displayFiles(File pixelArtFile) to fully execute.
Could you please show me the most straight forward way to solve this problem using the pseudo code for a more completed solution?
I have tried Runnables, Platform.runLater(), FutureTask<Void>, etc. and I'm pretty confused as to how they are meant to work and exactly coded.
I also have the two UI windows posted on the web at: Virtual Art. I think the pixelArtFile shown in the Pixel Array window may clarify the problem.
THANKS
Don't sleep the UI thread. A Timeline will probably do what you want.
List<File> files;
int curFileIdx = 0;
// prereq, files have been appropriately populated.
public void runAnimation() {
Timeline timeline = new Timeline(
new KeyFrame(Duration.seconds(5), event -> {
if (!files.isEmpty()) {
displayFile(curFileIdx);
curFileIdx = (curFileIdx + 1) % files.size();
}
})
);
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
}
// prereq, files have been appropriately populated.
public void displayFile(int idx) {
File fileToDisplay = files.get(idx);
// do your display logic.
}
Note, in addition to the above, you probably want to run a separate task to read the file data into memory, and just have a List<ModelData> where ModelData is some class for data you have read from a file. That way you wouldn't be continuously running IO in your animation loop. For a five second per frame animation, it probably doesn't matter much. But, for a more frequent animation, such optimizations are very important.
From my research I can see I am getting a vector issue (it looks like I divide by 0 but I don't do an divisions in my script).
I checked every script I have for positions and tried to catch it between trace statements. Couldnt do it. It looks like its in some update or fixed update but I have no clue where.
This error comes up SOMETIMES right as an enemy is killed.
I feel it has something to do with its position. Clicking on this error does nothing, but SOMETIMES it highlights the gameobject that got the bad transform passed to it.
Is there somewhere in your code I could get getting a NAN vector that I can look for?
Right as an enemy dies I will get a lot of these, and once its dead (destroyed) this problem goes away. It will play through a bit of animation, triggering the error each frame, and then when the enemy dies the error stops.
Clicking the error will only highlight the gameobject but will not open to a script where this occurs.
It comes up maybe 1 in 5 times whenever an enemy is killed...
Here is the enemy dying script (it doesn't set positions so the problem likely does not lie here)
public void killSelf()
{
_animator.SetBool("isAttacking",false);
_animator.SetBool("isDead",true);
StartCoroutine(processKillSelf());
}
IEnumerator processKillSelf()
{
yield return new WaitForSeconds(1f);//its a 30 frame animation
Destroy(gameObject);
}
Is there a way to FORCE unity3D to break on this error and let me look up the stack trace?
Not having the stack trace is the only reason I can't find where this is occurring.
I know this is late but I just had a similar problem and maybe it helps someone in the future.
As you already noticed this always happens if somwhere you try to devide a value by 0.
In my case I just couldn't find where I possibly divided by 0 that easy and unfortunately something like
try
{
transform.position = possiblyBrokenVector3;
}
catch
{
}
didn't catch it either so I couldn't set up proper brakepoints since it was called in Update.
What you always can do is actually checking the values for NaN. I directly made it an extension method for checking Vector3:
public static Vector3Extensions
{
public static bool ContainsNaN(this Vector3 vector)
{
return float.IsNaN(vector.x) || float.IsNaN(vector.y) || float.IsNaN(vector.z);
}
}
Now I can always check before I assign like
if(possiblyBrokenVector3.ContainsNaN)
{
Debug.LogWarning("Ignoring a NaN vector here!", this);
}
else
{
transform.position = possiblyBrokenVector3;
}
set a Brakepoint on the Debug line and finally step through the call history to see how the broken input value actually was produced.
Without seeing more of your code I can't say for sure but it sounds like reference is not being updated internally (ie. something is pointing to a vector that has already been destroyed.) I would poke around your animation code to see if that turns up anything.
For what its worth Object.Destroy has an optional second argument that is a delay timer. ( http://docs.unity3d.com/ScriptReference/Object.Destroy.html ) so you could re-write your code like this:
public void killSelf()
{
_animator.SetBool("isAttacking",false);
_animator.SetBool("isDead",true);
Destroy(gameObject, 1f);
}
and totally omit the processKillSelf() coroutine.
I found the problem:
It was not the character, but an HP bar on the character. The local scale of that HP bar was having one of the values set to 0 on death. Making sure the value is at least 0.1f fixed this problem:
float x = _hpBarMaxScale * health/healthmax>0?(_hpBarMaxScale * health/healthmax):0.1f;
hpBar.transform.localScale = new Vector3(x,hpBar.transform.localScale.y,hpBar.transform.localScale.z);
I'm currently working on a game that will randomly generate a dungeon for the player. This is made up of a whole heap of different methods being called from different files. I seem to have the code working to be able to calculate how much space is available on the other side of the door.
There is a catch however; the code only seems to work when I am outputting to the console using CCLOG. I wrote a good chunk of the code without testing and decided to then work through it in steps to see how the code worked (I figured I would just get it to run without bugs and next I will check my values).
After I had established that the code was successfully checking available space in each direction, while listing the locations it had checked, I decided that I would like to remove the CCLOG output. Unfortunately though, doing this caused the code to stop working.
//First check "forward"
bottom = CGPointMake(startLocation.x + forwardDirectionModifier.x, startLocation.y + forwardDirectionModifier.y);
top = bottom;
do
{
currentLocation = CGPointMake(top.x + forwardDirectionModifier.x, top.y + forwardDirectionModifier.y);
tileType = [tileCache getTileType:currentLocation];
if (tileType == TileTypeFiller)
{
top = currentLocation;
CCLOG(#"Top location is %#", NSStringFromCGPoint(top));
}
} while (tileType == TileTypeFiller || top.y != 63);
This is a small snippet from the code; It is the section of code I think is most likely the issue. Essentially the problem is that if I comment out or delete the line CCLOG(#"Top location is %#", NSStringFromCGPoint(top)); it will stop working.
Here are some more details:
I have several little chunks of code like this, as long as I CCLOG in each one, it will be able to move to the next. If i were to comment out any of them, it would stop progress to the next chunk.
I can change the CCLOG to output anything and it will still work, it just has to be there.
I have tried cleaning the project.
There are more CCLOG's that aren't used inside any loops and they can be removed without consequence.
Does anyone have a solution to this? As far as I can tell, whether I do or do not output something to the console,it shouldn't have an effect on whether or not the code will execute.
Thanks in advance.
EDIT: At Ben Trengrove's suggestion, I am adding in further examples of where the CCLOG is being used.
This code immediately follows the previously listed code.
//Check left relative to door
farLeft = CGPointMake(startLocation.x + leftDirectionModifier.x, startLocation.y + leftDirectionModifier.y);
do
{
currentLocation = CGPointMake(farLeft.x + leftDirectionModifier.x, farLeft.y + leftDirectionModifier.y);
tileType = [tileCache getTileType:currentLocation];
if (tileType == TileTypeFiller)
{
farLeft = currentLocation;
CCLOG(#"Far Left location is %#", NSStringFromCGPoint(farLeft));
}
} while (tileType == TileTypeFiller || farLeft.x !=0);
//Check forwards from far left
top2 = farLeft;
do
{
currentLocation = CGPointMake(top2.x + forwardDirectionModifier.x, top2.y + forwardDirectionModifier.y);
tileType = [tileCache getTileType:currentLocation];
if (tileType == TileTypeFiller)
{
top2 = currentLocation;
CCLOG(#"Top2 location is %#", NSStringFromCGPoint(top2));
}
} while ((tileType == TileTypeFiller)|| (top2.y != 63));
What does your tile cache return as a tileType when there is no tile at currentLocation ? TileTypeFiller by any chance ? if yes, you have an almost certain never ending loop there, under the right circumstances..
EDIT :
please add a line after the loop
CCLOG(#"");
and place a breakpoint on that line. See if the program stops there.
So the problem has now been solved, it seems that in part there was a fault in my logic.
Here is what I've done that now works:
do
{
currentLocation = CGPointMake(top.x + forwardDirectionModifier.x, top.y + forwardDirectionModifier.y);
tileType = [tileCache getTileType:currentLocation];
if (tileType == TileTypeFiller)
{
top = currentLocation;
}
locationCount++;
} while ((tileType == TileTypeFiller) && (locationCount != 15));
CCLOG(#"Top location is %#", NSStringFromCGPoint(top));
The change is that I've switched to AND as opposed to OR. I also changed the second part of the while as I realised that due to my max room size, I never needed to check more than 15 locations in any given direction.
Thanks a lot to everyone that has helped. I'm still not entirely sure though how the use of CCLOG was somehow able to help get past a fault in logic but at least it is working now.