Initialize superclass variables (necessary in the constructor) in the subclass

I am writing a simple asteroid clone game using Swing to display graphics. I kind of follow the lessons of Derek Banas , but decided to expand myself.

The initial idea is that every graphic element in the game (i.e. asteroids, spaceship and bullets) extends the Polygon class. Their constructor will look something like this:
 public class SpaceShip extends Polygon { //x and y coordinates public static int[] polyXArray = {...}; public static int[] polyYArray = {...}; //other class variables {...} public SpaceShip() { super(polyXArray, polyYArray, polyXArray.length); } } 

And it will be similar to other graphic elements.

EDIT: The key element here is that the two arrays do not preserve the actual coordinates of the objects, but their position relative to their center, the coordinates of which are double -type class-variable. Thus, arrays describe only the shape of the object, while the subclass method move() will affect the central coordinates. The class responsible for the actual drawing will call the move() method, and then apply the affine transformation to move and rotate the shape (according to the specified angle parameter). I do this to avoid the exact problems associated with working with double arithmetic.

Now, since the elements share many β€œequal” variables (their center coordinates, which I need to translate them with affine transformation, their speed components, etc.) and methods (getters and setters, move() , etc. ) I was thinking of making them an extension of an abstract class β€” say, GameShape β€” that contains all these common methods and variables. GameShape will now be as follows: 21> 21>

 public abstract class GameShape extends Polygon { //x and y coordinates, still unassigned public static int[] polyXArray, polyYArray; //other class variables {...} public GameShape() { super(polyXArray, polyYArray, polyXArray.length); } } 

Then I would like to set the desired value to polyXArray and polyYArray when I define different subclasses to draw the different shapes that I need, but I could not find a way to do this.

I want these variables to be static, because they are specific properties of individual classes, and I would not want to pass them as a parameter every time I create a new object.

My situation is very similar to the one described in this question , but the proposed solution does not seem to work, since I need the same variables in the constructor, is there a way to overcome - or around - this problem? Regardless of the procedure, my main goal is to have a superclass common to all graphic elements in order to avoid dozens of lines of code with copying.

+5
source share
6 answers

EDIT:

As stated in the VGR comments, this will not compile. So, we will have to slightly change the implementation, namely, we will use the HAVE relationship instead of the IS relationship :-)

First of all, do not put poly array fields. If you do, they will be the same for all subclasses, so what's the point?

Secondly, use a design pattern template . Your class will look something like this:

 public abstract class GameShape { //x and y coordinates, still unassigned public int[] polyXArray, polyYArray; private Polygon polygon; //other class variables {...} public GameShape() { instantiatePolyArrays(); this.polygon = new Polygon(polyXArray, polyYArray, polyXArray.length); } protected abstract void instantiatePolyArrays(); public final Polygon getPolygon(){ return this.polygon; } } 

Each expanding class will have to override this method, and you can instantiate arrays for each of the classes in each of the method overrides.

In addition, the word about the IS-HAVE relationship problem - what you presented in your example, is an IS relationship in which the GameShape object is a Polygon , therefore, you need to call the super constructor and the problem with it. In my solution, this replaces the HAVE relation, in which the GameShape object has a Polygon object inside, which is accessed using the getPolygon () method. This allows you to have extra flexibility :-)

-1
source

You have pairs of arrays that describe the shapes of certain types of game objects. If different game objects can have different shapes, then they cannot use one pair of arrays, as it would if they were static properties of a common superclass of all classes of game objects. Different objects of the same type can share the same pair of arrays (assuming that they do not need to be modified for each object), which can correspond to those arrays that are static fields of classes of specific game objects. In this case, however, if you want the superclass of these classes to be able to access the correct form data for a given game object, then you must say what kind of form data it is.

There are two main ways to do this:

  • You can pass the corresponding arrays of shapes to the constructor of the superclass. You say you don’t want to do this, but I don’t understand why.

  • You can define access methods for a superclass that must override subclasses to provide the correct form data (this is called a template template template).

+2
source

Array fields cannot be static because different shapes have different coordinates. Also, you do not need these arrays in certain subclasses, because they are already in Polygon or GameShape .

Here is more or less how I write GameShape (although I agree with @Michael that you do not need to pass both polyXArray and polyXArray.length to the constructor).

 public abstract class GameShape extends Polygon { // I got rid of the array fields as I think they are in Polygon anyway. //other class variables {...} // I added arguments to your constructor. public GameShape(int[] polyXArray, int[] polyYArray) { super(polyXArray, polyYArray, polyXArray.length); } } 

The problem is that super should be the first line of the constructor, but you can do this using private methods to build arrays:

 public final class BoringRectangle extends GameShape { public BoringRectangle(int left, int right, int top, int bottom) { super(xArray(left, right), yArray(top, bottom)); } private static int[] xArray(int left, int right) { return new int[] {left, right, right, left}; } private static int[] yArray(int top, int bottom) { return new int[] {bottom, bottom, top, top}; } } 
+1
source

The solution to this question will work if your classes will NOT extend the form, but provide forms through accessor + private static field.

 public abstract class GameObject { ... public abstract Polygon getShape(); 

It also helps to avoid duplication of form.

+1
source

If you really want to initialize things in your constructor, just call empty super(); and then loop against the abstract getPolyXArray() and getPolyYArray() to send addPoint .

 public abstract class GameShape extends Polygon { public GameShape() { super(); final int length = getPolyXArray().length; for (int i = 0; i < length; i++) { addPoint(getPolyXArray()[i], getPolyYArray()[i]); } } public abstract int[] getPolyXArray(); public abstract int[] getPolyYArray(); //common stuff... } public class Asteroids extends Polygon { public int[] getPolyXArray() { return new int[]{1, 2, 3}; } public int[] getPolyYArray() { return new int[]{1, 2, 3}; } } 
+1
source

I think polyXArray and polyYArray are in the Polygon class; that where they belong. Therefore, it’s nice to have duplicate fields. Also, get rid of ned to call the super constructor. I would develop a class structure as follows:

 public class SquareShape extends Polygon { private int size; public SquareShape(int x, int y, int size) { this.size = size; int[] xpoints = new int[4]{ x - size / 2, x - size / 2, x + size / 2, x + size / 2 }; int[] ypoints = new int[4]{ y - size / 2, y + size / 2, y + size / 2, y - size / 2 }; setXArray(xpoints); setYArray(ypoints); } } 

This way you can ensure that all SquareShape objects SquareShape indeed square in shape, but you can customize everything you need to customize. Similar position and size, which should not be static common fields. setXArray and setYArray must be protected methods found in Polygon . You do not want the outside world to mess with individual points. You can add public getters, though.

Note

You might want to consider one array of a complex Point type, rather than two closely related and dependent arrays. I feel that this will greatly simplify the many tasks in your project.

0
source

Source: https://habr.com/ru/post/1233203/