Best way to debug?

So, I have around 26 files for my game, and I just went through updating them so that it’s more object oriented and not hardcoded.

I thought everything was good, i made sure there were no infinite loops, and when i start the game up everything loads in, but after a couple of seconds it freezes and acts as if it’s stuck in an infinite loop.

I also noticed when i start it up, I can move my player around, but I can’t shoot.

Pretty much, I just shoot by pressing the M key.

When I click M, it runs currentWeapon.attack()

the currentWeapon is made in an inherited class, the Creature constructor.

Pretty much, I needed to save the “shooter” when I create the weapon, so I pass “this” in the arguments for the weapon, and within the weapon I use that for the x,y,width,height, and direction of the creature. (Where to spawn the bullet the weapon shoots). This worked when I hardcoded everything, but I’m wondering could this issue of the game freezing be cause because of how I create the weapon/Pass the creature? I also wonder if I pass it through the constructor, would that mean the data is never updated. Cause i set “this” to a local variable in the weapon. I don’t really know what else to do unless I need to pass the creature every time I want to attack/draw.

MY question though is, what’s the best way to find the issue for something like this? I could see when you have a large game with 100+ files… it may get kinda tricky to fix an issue like this.

Most large games require testing each new class or feature as it’s added, which eliminates most problems like this.

Launch the game in your IDE in Debug mode.
Once you suspect your game enters some loop, freeze the thread you suspect is ‘stuck’, and look at the stacktrace.
Then step though the code until you figure out what is happening.

Or… litter your code with logging, until you figure out what’s the culprit.

Some people prefer using a step-debugger process. Others prefer to embed print messages to the console at key spots revealing, key data.

I’ve seen books were the preference was asked of some of the greatest programmers alive, and some prefer one, or the other, or a mix of both. There was no clear winner.

I lean towards printing console messages, and use the following basic form:

System.out.println("classname.methodname, variable=" + variable);

A lot of people would think this is overkill, but I really hate having old messages appear and not know where the heck they are coming from. Hence: the inclusion of the class and method names.

You don’t necessarily have to put these in every one of your 100+ files. For example, you can pick a single entity that is unable to shoot, focus on that. Chances are that what you learn will be applicable to parallel situations. Also you can scatter these through various stages of you process, to try to narrow the possibilities of where the hang is occurring.

In situations where you want to look at a statement that repeats a huge number of times, and you don’t want to flood the console, you can add a counter and only print every 1000th iteration or whatever is a useful count.

[EDIT] Riven’s advice on using the debug to identify a hanging thread is really good. I will use this more in the future.

I may have just realized something.

If I pass something, let’s say an ArrayList in like the constructor, and set it to a local variable, will that local variable always have the most up to date version of the ArrayList? I thought it would be a copy… xD, or do objects work differently? I guess my player is working fine shooting, and it’s all based on “this” which is from the Creature constructor, and it’s set to a local variable in my gun class.

If you pass in an object somewhere and change it, it will change it everywhere :slight_smile: the power of objects!

but if i set it to a golbal variable in another objects class… it’s still referenced when i access that global variable? Even if the original one is changed a bunch?

You know you can write a simple program to test things like that, right?

[quote]If I pass something, let’s say an ArrayList in like the constructor, and set it to a local variable, will that local variable always have the most up to date version of the ArrayList? I thought it would be a copy…
[/quote]
Rule of thumb for how Java operates: no instance of a reference type is ever copied unless you do it explicitly somehow (e.g. clone() or a custom deep copy function).

This is plainly seen when you realize that the constructor parameter and local variable you mention are not the arraylist itself, but pointers to it. You’re assigning the local variable pointer to point at some list, not copying the list.

If I understand, you’re asking if you have a bunch of variables inside a class and change those variables somewhere else then is it still referencing the same object? Or are you asking if you pass in the object to a variable of the same object type, does it make a copy or does it still reference the same object?

Both cases give the same result. You are passing the reference of an object and if you pass that reference to another variable, it is still the same reference

EDIT: This is known as a shallow copy. If you want to copy an object with it’s own variables then you need to create a deep copy

I’m silly.

MoveableTile copy;

Public Object(MoveableTile shooter)
{

 copy = shooter;

}

this makes a shallow copy cause it’s not making a new shooter?

MoveableTile copy;

Public Object(MoveableTile shooter)
{

 copy = new shooter; (or something like that, idk)

}

It would create a new instance of that object I assume?

I’ve never really worked with pointers or anything, but even after testing I always thought it made a copy. I swear, things they teach you in school are very misleading at times.

Thanks for the info.

[quote]this makes a shallow copy cause it’s not making a new shooter?
[/quote]
No. There is no copy at all.

No. There is no copy at all.
[/quote]
This is a reason that it shouldn’t be called a shallow copy :-\ it’s just referencing the object

Edit:

Just been reading about something called a copy constructor. You create a constructor inside the class you want to copy that’s parameters take an object of the class type like so: public Dog(Dog dogToCopy). You can then call something like this inside another constructor/method:


// Maybe this class is a person that wants an exact copy of the original dog
private Dog dog
public void copyOfDog(Dog dogInstance){
    this.dog = new Dog(dogInstance)
}

You then set all the fields inside Dog equal to ToCopy like so:


public Dog(Dog dogToCopy){
    age = dogToCopy.getAge();
    weight = dogToCopy.getWeight(); // etc
}

This creates an exact copy of the original dog BUT it never updates the variables if the original changes as it creates a whole new object and is not referencing the same object. Clever stuff!

It’s not called a shallow copy…

`
a = new …();
b = a; // alias
c = a.shallowCopy(); // shallow
d = a.deepCopy(); // deep

±–+ ±–+
| 1 |<--------+ | 3 |
±^-+ | ±^-+
| | |
±–+ ±–+ ±–+
| 1 |<–+ | 2 | | 3 |
±^-+ | ±^-+ ±^-+
| | | |
a b c d
`

EDIT: that copy constructor is an example of a shallow copy. A deep copy (e.g. a correctly implemented clone()) also recursively copies reference-type fields.

:o It… it’s not? I’ve read on multiple sites now as it called that. Strange ???

Edit: I’ve also read that clone is broken and full of holes and so a lot of people avoid it?

In his code: copy = shooter; is not a shallow copy, it’s an alias (Java’s standard operating procedure).

Ooooo. So a shallow copy is where we actually do copy the object and don’t just reference it? A deep copy is where we change the fields as a unique copy and an alias just points to the object?

Yes.

Alias: copy a pointer.
Shallow: copy contents of object into new object, return pointer to new object. (which may contain aliased fields)
Deep: copy contents of object, recursively shallow copy any references in the contents, return pointer to new object hierarchy containing no aliases to original hierarchy anywhere.

Ah, thanks for clearing that up :slight_smile: a shadow copy should fit most cases, right?

slaps medal on pizza ;D

Welp, I guess I misunderstood a lot of things in java regarding objects :/. Seriously though, they don’t explain this correctly in school.

Say you have a class like this:

class Thing{
   private String thing;

   public Thing(String thing){
      this.thing = thing;
   }

   public void setThing(String thing){
      this.thing = thing;
   }
 
   public String getThing(){
      return thing;
   }
}

And you then have a List of instances of that class:

List<Thing> things = new ArrayList<>();
things.add(new Thing("zero"));
things.add(new Thing("two"));
things.add(new Thing("three"));

You can make a shallow copy of that List just by copying over those instances into a new List:

List<Thing> moreThings = new ArrayList<>();
moreThings.addAll(things);
moreThings.add(new Thing("four")); //won't affect the first things List

However, since all you’ve done is copy the references to the existing Things into a new List, your new List is still pointing to the Things in the first List. In other words, changes to Things in the first List will be reflected in the second List:

things.get(0).setThing("uh oh");
System.out.println(moreThings.get(0).getThing());//prints "uh oh"

This will cause weird behavior if your code uses that second List to modify the Thing instances in a way that the first List wasn’t expecting. To avoid that, you can make a deep copy by actually making copies of the Thing instances:

List<Thing> deepCopy = new ArrayList<>();
for(Thing thing : things){
   Thing deepCopiedThing = new Thing(thing.getThing());
   deepCopy.add(deepCopiedThing);
}

Now your deepCopy List contains copies of the original Things, so changes to the instances in the deepCopy List will not be reflected in the original List:

deepCopy.get(1).setThing("six");
System.out.println(things.get(1).getThing()); //prints "one"

This is a simplified example, but those are the basics. Sometimes shallow copies are fine, and perhaps even preferable: it can be very complicated, very expensive memory-wise, or even downright impossible to create deep copies all the time. Which approach you take really depends on what you’re trying to do.