I am new to java inheritance and I have been trying to create a game.
This game has a game object abstract class and I created a Enemy class that extends it. Now I want to add multiple types of enemies to extend Enemy. I am trying to find the most efficient way to do this however I can not figure out how to give the sub class final properties that can be used by the super if that makes sense. For instance, I want all the enemies to have a speed in the X direction and the Y direction, but I want each type of enemy to have their own.
The way I have it now, is basically pointless because even if I create an FastEnemy, I have to put it all in the constructor when I create the object. This is probably really simple, I am just new and never ran into this before.
package first.Game;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
public class Enemy extends GameObject{
private Handler handler;
private Color c;
private int eWidth, eHeight, speedX, speedY, x, y;
public Enemy(int x, int y, int eWidth, int eHeight, int speedX, int speedY, Color c, ID id, Handler handler)
{
super(x, y, id);
this.x = x;
this.y = y;
this.id = ID.Enemy;
this.c = c;
this.eWidth = eWidth;
this.eHeight = eHeight;
this.handler = handler;
this.speedX = speedX;
this.speedY = speedY;
}
public Rectangle getBounds()
{
return new Rectangle(x, y, eWidth, eHeight);
}
public void tick()
{
x += speedX;
y += speedY;
if(y <= 0 || y >= Game.HEIGHT - 48) speedY *= -1; //What can I do instead of 48?
if(x <= 0 || x >= Game.WIDTH - 32) speedX *= -1;
handler.addObject(new Trail(x, y, ID.Trail, c, eWidth, eHeight, 0.03f, handler));
}
public void render(Graphics g)
{
g.setColor(c);
g.fillRect(x, y, eWidth, eHeight);
}
}
package first.Game;
import java.awt.Color;
public class FastEnemy extends Enemy{
public FastEnemy(int x, int y, int eWidth, int eHeight, int speedX, int speedY, Color c, ID id, Handler handler)
{
super(x, y, eWidth, eHeight, speedX, speedY, c, id, handler);
}
}
From your comment
handler.addObject(new BasicEnemy(r.nextInt(WIDTH - 64), r.nextInt(HEIGHT - 64), 16, 16, 5, 5, Color.red, ID.Enemy, handler)); This is what I have to do right now. But if I have to give them all those sizes everytime… then really there is no difference between the different types of enemies. It is just an enemy that I have to manually change everytime I create one.
If the values of the speed and size are constants and the value depends on an enemy type, it can be placed within the class itself. You take only the other variables as parameters.
public class FastEnemy extends Enemy {
public FastEnemy(int x, int y, Color c, ID id, Handler handler)
{
super(x, y, 16, 16, 5, 5, c, id, handler);
}
}
You can initialize the Color and ID too in the same way (if they are constants)
There are many things you can do. One thing you can do is make whatever variable you want updated in the objects constructor method. For example, in the constructor method for the fast enemy, you can update the speed to 5 if the normal speed is something like 3. Also, since methods are overridden, you can override a get method for whatever variable you want, and each object returns its unique value through the get method.
I'm assuming that you don't know method overriding. It is a pretty complicated subject, but here is the basic run-down: If there is one object extending another object, if the parent class has one object that the child class wants to do differently, it can just declare that method in its own class with everything the same except the method body. If you didn't get it, here is an example.
This is just basic pseudo code, it's not really following the exact syntax of java.
class Tree {
public void print() {
print "I am a tree"
}
}
Then there is this other class that extends it.
class BirchTree {
// Note the public void is the same. You can somewhat modify that, but thats a little more complicated.
public void print() {
print "I am a birch tree"
}
}
So, it another class hold a Tree object, but it is really a birch tree, when they call the print method, instead of printing "I am a tree," it prints "I am a birch tree."
If you don't want that, you can use the other variation. In the constructor method, you can set that variable to whatever you want.
class Tree extends BiggerTree {
int height;
Tree(int height) {
// If the user created this object expecting it to be something else, then just the parameter.
height = 10; // If a bigger tree's height is usually 15 or something.
this.height = height;
}
Hope this made sense.
If you don't want to put the speed in the constructor every time you could just have multiple classes (assuming that you want static speeds for each speed type of enemy)?
public class Enemy
{
private Handler handler;
private Color c;
private int eWidth, eHeight, speedX, speedY, x, y;
public Enemy(int x, int y, int eWidth, int eHeight, int speedX, int speedY, Color c,
ID id, Handler handler)
{
super(x,y,id);
this.x = x;
this.y = y;
this.c = c;
this.eWidth = eWidth;
this.eHeight = eHeight;
this.handler = handler;
this.speedX = speedX;
this.speedY = speedY;
}
public int getSpeedY() //test function
{
return this.speedY;
}
}
public class FastEnemy extends Enemy
{
public FastEnemy(int x, int y, int eWidth, int eHeight, Color c, ID id, Handler
handler)
{
super(x, y, eWidth, eHeight, 5,5,c,id,handler); //sets a static value for
//speed and passes it to the
//super function for enemy
}
}
public class NormalEnemy extends Enemy
{
public NormalEnemy(int x, int y, int eWidth, int eHeight,Color c, ID id, Handler
handler)
{
super(x, y, eWidth, eHeight, 3,3, c, id, handler);
}
}
public class SlowEnemy extends Enemy
{
public SlowEnemy(int x, int y, int eWidth,int eHeight,Color c, ID id, Handler
handler)
{
super(x,y,eWidth,eHeight,1,1,c,id,handler);
}
}
public static void main(String[] args)
{
Main m = new Main();
FastEnemy newEnemy = m.new FastEnemy(1,2,4,4,c,id,handler); //just a test
instance
SlowEnemy otherEnemy = m.new SlowEnemy(1,2,3,3,c,id,handler); //just a test
instance
System.out.println(otherEnemy.getSpeedY()); //just a test print
}
}
But if you want to make a custom speed for every enemy, then your best bet is just using constructors every time.
Since you seem to be annoyed with having to manually input for stuff every time you make an enemy, I would just make a bunch of set variables or classes related to size, speed, etc. But the more custom you want to make your enemies, the more stuff you're gonna have to do manually.
This is using Processing 3.5, not every java thing works the same here.
The Bird class is giving me the error saying it needs to implement call(). Isn't it already under the main? I'm not experienced with interfaces so I don't know what exactly is going on here.
public interface FuncCall<A> {
A call();
}
class Bird implements FuncCall{
//Error here ^
//The type FuncCallTest.Bird must implement the inherited abstract method FuncCallTest.FuncCall.call()
//Is this not implemented already under main?
float x, y, size;
ArrayList<FuncCall<Float>> inputs = new ArrayList<FuncCall<Float>>();
public Bird(float x, float y, float size){
this.x = x;
this.y = y;
this.size = size;
}
public void main(String[] args){
FuncCall<Float> getX = new FuncCall<Float>(){
#Override
public Float call(){
return x;
}
};
FuncCall<Float> getY = new FuncCall<Float>(){
#Override
public Float call(){
return y;
}
};
FuncCall<Float> getSize = new FuncCall<Float>(){
#Override
public Float call(){
return size;
}
};
inputs.add(getX);
inputs.add(getY);
inputs.add(getSize);
}
}
class Pol {
ArrayList<FuncCall<Float>> inputs = new ArrayList<FuncCall<Float>>();
public Pol(ArrayList<FuncCall<Float>> inputs){
this.inputs = inputs;
}
//public float call(ArrayList<FuncCall<Float>> arr, int index){
//return arr.get(index).call();
//}
//How do I do this? Do I need to implement the interface here as well? Because if so same error as on Bird
}
I'll also stick this extra bit on the end here.
System.out.println(pol.call(pol.inputs, 1));
Does will that work? It doesn't error before compiling.
I appreciate any help. Please ask if something doesn't make sense as I'm still new to stack and not the best with java. :)
main file :
void setup(){
Bird bird = new Bird(1.2, 3.2, 7.5);
Pol pol = new Pol(bird.inputs);
System.out.println(pol.call(pol.inputs, 1););
}
First of all you could skip your FuncCall interface and use Java's Supplier functional interface and just add these Suppliers respectively method references of your class objects getters to the list.
Another approach is to provide an interface or abstract class that has getters and/or member variables for x, y and size and use this interface or abstract class as type parameter for the list.
With Suppliers:
This is closer to your example and requires less changes in
your code.
The second option with an interface changes your Pol class
completely and I am not sure if this is acceptable for you.
´
public class Bird {
private float x;
private float y;
private float size;
public Bird(float x, float y, float size) {
//set your members here
}
public Float getX() {
return this.x;
}
public Float getY() {
return this.y;
}
public Float getSize() {
return this.size;
}
}
´
Then the Pol class
´
public class Pol {
private final List<Supplier<Float>> inputs;
public Pol(List<Supplier<Float>> inputs) {
this.inputs = inputs;
}
public Float call(int index) {
return this.inputs.get(index).get();
}
}
´
And your main should look like
´
public static int main(String[] args) {
Bird bird = new Bird(1.0f, 1.0f, 2.5f);
Pol pol = new Pol(Arrays.asList(bird::getX,
bird::getY, bird::getSize));
Float birdsSize = pol.call(2);
return 0;
}
´
I have two classes, one called Soldier, and one called Battlefield, the soldier can spawn at any location that is within the battle field dimensions that are specified by the parameter of the battle field
the variables that put the Soldier object on x and y axis are:
private double xPos;
private double yPos;
those are within the Soldier class
the method for spawning the Soldier object on the battle field are
public Soldier(double speed) {
this.speed = speed;
xPos = (int) (Math.random() * Battlefield.getX());
yPos = (int) (Math.random() * Battlefield.getY());
}
And within the battle field class
private static double x;
private static double y;
public static double getY() {
// TODO Auto-generated method stub
return y;
}
public static double getX() {
// TODO Auto-generated method stub
return x;
}
Main Method,
public class Battle {
//Main method where three battles are run.
public static void main(String[] args) {
Battlefield k = new Battlefield(100, 100);
Battlefield b = new Battlefield(100, 100);
Battlefield c = new Battlefield(100, 100);
}
}
the problem I am having is this way of doing it is causing the first object to not have any coordinates and everything after that seems fine, but why?
From the main class, it looks like you want each Battlefield to have its own state... So don't make Battlefield.x and Battlefield.y static or else they will all be the same.
Where is the constructor for Battlefield?
I want to spawn my item (Sword1) in random places. When i spawn it, first of all it only creates 1 of it, then it moves randomly everywhere. Should I create and array for the object? How?
public class Sword1 {
public static TextureRegion sprite;
public static int x;
public static int y;
public static int size;
public static boolean created;
public Sword1(){
created=true;
Random r = new Random();
x = (r.nextInt(5)+1)*GameRender.tilesize;
y = (r.nextInt(5)+1)*GameRender.tilesize;
size = GameRender.tilesize;
sprite = AssetLoader.s1;
createMe();
}
public static void createMe() {
GameRender.batch.draw(sprite, x, y, size, size);
}
}
I render it in batch:
while(number<4){
number++;
Items.createSwords();
}
I also tried to use Items class that would hold all the Items when there would be more
public class Items {
public Items(){}
public static void createSwords() {
Object sword = (Sword1) new Sword1();
}
}
You can clean up and rename a bit the Sword1 class [I also changed the static variables to private] otherwise they will be shared across the various class instances see: Static Variables — What Are They?.
public class Sword {
private TextureRegion sprite;
private int x;
private int y;
private int size;
public Sword() {
Random r = new Random();
x = (r.nextInt(5)+1)*GameRender.tilesize;
y = (r.nextInt(5)+1)*GameRender.tilesize;
size = GameRender.tilesize;
sprite = AssetLoader.s1;
}
public void createMe() {
GameRender.batch.draw(sprite, x, y, size, size);
}
}
Then to have multiple swords you can use and an ArrayList of Swords the class that is using the Sword object GameRender as given in comment:
private List<Sword> swords = new ArrayList<Sword>();
for more info on Array see the Oracle documentation
Now you would have a List of Swords objects. This list will be used to store the newly create Sword objects and to render them later.
create swords
//create 10 swords
for (int i = 0; i<10 ; i++ ) {
swords.add(new Sword());
}
render swords , call the create method in each object
for (Sword sword : swords) {
sword.createMe();
}
for example a minimal example in the GameRender Class
public class GameRender() {
private List<Sword> swords = new ArrayList<Sword>();
public GameRender(){
// create the swords
for (int i = 0; i<10 ; i++ ) {
swords.add(new Sword());
}
// render the swords
public void render() {
for (Sword sword : swords) {
sword.createMe();
}
}
}
This is my first class called class circle:
public class circle
{
//circle class begins
//declaring variables
public double circle1;
public double circle2;
public double circle3;
public double Xvalue;
public double Yvalue;
public double radius;
private double area;
//Constructor
public circle(int x,int y,int r)
{//constructor begins
Xvalue = x;
Yvalue = y;
radius = r;
}//constructor ends
//method that gets the area of a circle
public double getArea ()
{//method getArea begins
area = (3.14*(this.radius * this.radius));
return area;
}//getArea ends
public static smaller (circle other)
{
if (this.area > other.area)
{
return other;
else
{
return this;
}
//I'm not sure what to return here. it gives me an error( I want to return a circle)
}
}//class ends
}
This is my tester class:
public class tester
{//tester begins
public static void main(String args [])
{
circle circle1 = new circle(4,9,4);
circle circle2 = new circle(4,7,6);
c3 = c1.area(c2);
System.out.println(circle1.getArea());
//System.out.println(
}
}//class tester ends
The smaller method should have a return type. Also the this keyword cannot be used in a static method. i.e. the method will not have access to the instance of Circle. This make sense given what the method name smaller implies - it compares the current instance of Circle with another passed in.
public Circle smaller(circle other) {
if (this.area > other.area) {
return other;
} else {
return this;
}
}
To use:
Circle smallerCircle = circle1.smaller(circle2);
Aside: Java naming conventions show that class names start with an uppercase letter to give Circle.
Area is unassigned when you make the operation :
c3 = c1.area(c2);
You need to make the GeArea() call before you can use the area field of the class.
So for example:
circle circle1 = new circle(4,9,6);
circle circle2 = new circle(4,7,6);
circle2.area = c1.getArea();
That is assuming that the c3 var you're trying to assign to has been instantiated as a circle.
You simply forgot a closing brace
if (this.area > other.area)
{
return other;
} //You forgot this brace and confused the compiler
else
{
return this;
}