Sign in to follow this  
robert4818

Java Question

Recommended Posts

robert4818    138
New to java (and programming in general), so I'm not sure my question is even possible.


I'm working with a program and I'm not sure how to (or if I can) do the following.

I'm working with multiple classes, one of which is my Primary class (it has the main).

During operation, I'm trying to call a method in another class. During the operation of the method, I need to manipulate and reference variables from the primary class. However, the manipulation is done in such a way that its not a "return" style.

(i.e. if an action occurs the player needs to lose a number from the lives variable in the primary class, but the method is more than just checking to see if the player lost a life.)

Is there a way to basically reference the primary class such as main.lives?



Share this post


Link to post
Share on other sites
SimonForsman    7642
You should rethink your design.

What you want to do is perfectly possible, just store the variables you need to modify in its own class (not the main class), create a instance of that class in the main method (as a local variable, not as a member of the primary class) and pass that instance as a parameter to the method that does the modifying.

However, you really should have the class owning the variables be responsible for modifying them since otherwise you'll most likely end up with a mess where you got code modifying for example the player state in 50 different locations.

The bad solution would look something like this:


//Player.java
public class Player {
public int lives;
}

//Game.java
public class Game {
public static void main(String args[]) {
Player player1;
player1.lives = 5;
bool gameIsRunning=true;
while (gameIsRunning) {
gameCode......
SomeOtherClass.methodThatModifiesLives(player1);
}
}
}

//SomeOtherClass.java
public class SomeOtherClass {
//This one is only static so that we dont have to create an instance of the class
public static void methodThatModifiesLives(Player p) {
p.lives--;
}
}




The better solution would be to move the code that reduces lives into the Player class and add the methods necessary for other classes to tell it what happened. (The player class should be responsible for what happens)

You could also make the lives variable global by declaring it as public static in the primary class and then access it as PrimaryClass.lives but thats even worse.

[Edited by - SimonForsman on October 16, 2010 2:55:08 AM]

Share this post


Link to post
Share on other sites
robert4818    138
Here's what I'm doing.

I'm using a class that extends the animapp class.

Part of that is the doFrame() method.

This portion of my the code is where all the magic happens, and everytime the frame refreshes, the code within it executes.

In the game that I'm working on, I want the doframe() instructions to be different based on what "screen" I'm on (start screen, flying, planet, etc.)

One way to handle this is to do a large amount of If thens that has the code nested within it based on the screen the code is in.

My thought on this was to instead create an action() method within the screen and under the doFrame() method have a much cleaner looking code.

public void doFrame()
{
__if(screen.equals("Start")
__{
____startScreen.action();
__}
__Elseif(screen.equals("space")
__{
____spaceScreen.action();
__}
}

Its a spaceship game, and an example of it would be that every frame the game checks to see if the players ship collides with an asteroid. If it does, the player loses a life. This check only needs to take place while in the space screen, and not the start screen, which is why I want to place this code within the spaceScreen.action() method.

Then it would be much easier (IMO) to go into the appropriate action() method to troubleshoot instead of looking through a long list of nested instructions.

Unfortunately that requires back-referencing to the sending class, and I'm unsure how to do this.

Share this post


Link to post
Share on other sites
SimonForsman    7642
Quote:
Original post by robert4818
Here's what I'm doing.

I'm using a class that extends the animapp class.

Part of that is the doFrame() method.

This portion of my the code is where all the magic happens, and everytime the frame refreshes, the code within it executes.

In the game that I'm working on, I want the doframe() instructions to be different based on what "screen" I'm on (start screen, flying, planet, etc.)

One way to handle this is to do a large amount of If thens that has the code nested within it based on the screen the code is in.

My thought on this was to instead create an action() method within the screen and under the doFrame() method have a much cleaner looking code.

public void doFrame()
{
if(screen.equals("Start")
{
startScreen.action();
}
Elseif(screen.equals("space")
{
spaceScreen.action();
}
}

Then it would be much easier (IMO) to go into the appropriate action() method to troubleshoot instead of looking through a long list of nested instructions.

Unfortunately that requires back-referencing to the sending class, and I'm unsure how to do this.


normally you wouldn't need back-referencing in this situation since the class containing the doFrame method shouldn't have anything worth referencing,

However since doFrame isn't static you can just pass "this"

so


public void doFrame() {
currentScreen.action(this);
}

public class SpaceScreen extends Screen {
public void action(WhateverClassThedoFrameMethodIsIn owner) {
owner.publicMethod(parameters);
owner.publicVariable=value;
}
}

Allthough there shouldn't be any sane reason for the "screen" to access the class that holds the doFrame method, if the screen needs access to other objects you should pass references to those objects to its constructor, From the looks of things spaceScreen is the only thing that actually uses the asteroids and player objects, so why not just let it own those ?

Share this post


Link to post
Share on other sites
robert4818    138
Quote:
Original post by SimonForsman
Quote:
Original post by robert4818
Here's what I'm doing.

I'm using a class that extends the animapp class.

Part of that is the doFrame() method.

This portion of my the code is where all the magic happens, and everytime the frame refreshes, the code within it executes.

In the game that I'm working on, I want the doframe() instructions to be different based on what "screen" I'm on (start screen, flying, planet, etc.)

One way to handle this is to do a large amount of If thens that has the code nested within it based on the screen the code is in.

My thought on this was to instead create an action() method within the screen and under the doFrame() method have a much cleaner looking code.

public void doFrame()
{
if(screen.equals("Start")
{
startScreen.action();
}
Elseif(screen.equals("space")
{
spaceScreen.action();
}
}

Then it would be much easier (IMO) to go into the appropriate action() method to troubleshoot instead of looking through a long list of nested instructions.

Unfortunately that requires back-referencing to the sending class, and I'm unsure how to do this.


normally you wouldn't need back-referencing in this situation since the class containing the doFrame method shouldn't have anything worth referencing,

However since doFrame isn't static you can just pass "this"

so


public void doFrame() {
currentScreen.action(this);
}

public class SpaceScreen extends Screen {
public void action(WhateverClassThedoFrameMethodIsIn owner) {
owner.publicMethod(parameters);
owner.publicVariable=value;
}
}

Allthough there shouldn't be any sane reason for the "screen" to access the class that holds the doFrame method, if the screen needs access to other objects you should pass references to those objects to its constructor, From the looks of things spaceScreen is the only thing that actually uses the asteroids and player objects, so why not just let it own those ?


Part of the problem is I'm not overly familiar with the AnimApp class. (I believe its a super class and as of yet we haven't touched super classes yet.)

As it is. I'm modifying this code below and greatly adding to it to create my game.

*This is the WORKING version of the code, not the bug riddled one.

It simply creates a circle that chases other circles and tries to touch them without hitting a tree circle...

It forms the basis of what I'm working on, but I'm adding in different parts of the game (for now I'm calling them "Screens". This one will switch between rooms of an array to form a small map, but currently all the doFrame() instructions are part of this parent class.


import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Random;

public class BirdGame extends AnimApp
{
private Bird a;
private Bird player;
private int k,t,l, points = 0, lives = 4;
private int bugcount = 5, treecount = 5;
private Room[] map;
private int room = 0;

public BirdGame()
{
super( "BirdGame", 500, 500, 33333333 );
}

public void prepare()
{
a = new Bird( 10, 250, 100, RGB.WHITE, 0, 45 );
player = a;

map = new Room [2];
map[0] = new Room();
map[1] = new Room();

map[0].prepare(bugcount, treecount);
map[1].prepare(bugcount, treecount);
}

public void doFrame()
{
a.draw();
a.fly();


for( t=0; t<map[room].trees.size(); t++ )
{
map[room].trees.get(t).draw();
if(a.treeCollision(map[room].trees.get(t)))
{
lives--;
room = 0;
if(lives>0)
{
a = new Bird( 10, 250, 100, RGB.WHITE, 0, 45 );
player = a;
}
else a = new Bird(0, 0, 0, RGB.BLACK, 0, 0);
}
}

for( k=0; k<map[room].bugs.size(); k++ )
{
map[room].bugs.get(k).draw();
map[room].bugs.get(k).fly();
Random generator = new Random();
l = generator.nextInt(100);

if(l<50)
map[room].bugs.get(k).dirn += 10;
else
map[room].bugs.get(k).dirn -= 10;

if(map[room].bugs.get(k).isOffSideEdge())
map[room].bugs.get(k).dirn = 180-(map[room].bugs.get(k).dirn);

if(map[room].bugs.get(k).isOffHorizEdge())
map[room].bugs.get(k).dirn = 360-(map[room].bugs.get(k).dirn);

if(a.bugCollision(map[room].bugs.get(k)))
{
points += map[room].bugs.get(k).points;
map[room].bugs.remove(map[room].bugs.get(k));
map[room].bugs.add( new Bug() );
}
}

if (a.isOffLeftEdge())
{
if(room == 1)
{
room--;
a.cx = 500 - a.radius;
}
else
a.cx = a.radius;
}

if(a.isOffRightEdge())
{
if(room == 0)
{
room++;
a.cx = a.radius;
}
else
a.cx = 500-a.radius;
}

if(a.isOffTopEdge())
a.cy = 450 - a.radius;
if(a.isOffBottomEdge())
a.cy = a.radius;

AALib.setColor( new RGB( 250, 250, 250 ) );
AALib.drawText("Score: "+points +" Lives: " + lives , 10, 450, .1, 0);
AALib.drawText("Room: "+ room, 300, 450, .1, 0);
if(lives == 0)
{
AALib.setColor( new RGB( 250, 250, 250 ) );
AALib.drawText("GAME OVER", 50, 250, .5, 3);
}

}

public void keyPressed( KeyEvent e )
{
int code = e.getKeyCode();
double dirnAmount = 5;
double speedAmount = 1;

if( code == KeyEvent.VK_LEFT )
{
player.turn( dirnAmount );
}
else if( code == KeyEvent.VK_RIGHT )
{
player.turn( -dirnAmount );
}
else if( code == KeyEvent.VK_UP )
{
player.accelerate( speedAmount );
}
else if( code == KeyEvent.VK_DOWN )
{
player.accelerate( -speedAmount );
}

}

public static void main(String[] args)
{
new BirdGame();
}

}


Part of the problem for me though is I'm clueless as to what to do to call this class.

Unlike other constructors, the new Birdgame() doesn't seem to be made with a variable name attached to it.

I've tried BirdGame.lives to see if it would even attempt to reference the lives variable and give me back a "Lives is set to private" error, but I don't get that.

I was hoping there was a generic "sender" or "back" style of code that would just instantly refrence the sending class.

Share this post


Link to post
Share on other sites
SimonForsman    7642
Inside the BirdGame class the instance is called "this" ("this" is a keyword in Java that always refers to the current instance)

So if you need the Bird class to access your BirdGame class you need to:
1) Add a BirdGame parameter to the Bird constructor
2) Create the Bird with player = new Bird(this, 10, 250, 100, RGB.WHITE, 0, 4);

Thus your Bird constructor will be something like:

private BirdGame bgame
public Bird(BirdGame game, int x, int y, int something, RGB color, int somethingelse, int anothernumber) {
bgame = game;
...
...
...
}


and any function in Bird can then access your BirdGame instance through the bgame variable.

Basically there is no way to directly reference the "sender" since its always unknown, the sender however can reference itself (Through the "this" keyword) and can send that reference as a parameter to another object if needed.

for example


//Test.java
public class Test {
public static void main(String args[]) {
new Sender();
}
}

//Sender.java
public class Sender() extends AnimApp {
public lives;
public void doFrame() {
lives=5;
Reciever reciever = new Reciever(this);
reciever.test();

//lives is now 4
}
}

//Reciever.java
public class Reciever() {
private Sender s;
public Reciever(Sender sender) {
s = sender;
}
public void test() {
s.lives--;
}
}




You could also pass "this" directly to the test method if you prefer.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this