Moving from Processing to Flash CS5, how do I get started? - java

I've been using Processing for around two years now, and I really like it. However, I feel like Flash is a bit more useful for coding games, as it's more universal and flexible. I'm starting to feel like I have no idea what I'm doing, and I really don't get any of the concepts like movie clips and the stage and so forth. In Processing, to make, say, a ball, I might make this:
Ball[] ballArray = new Ball[ 0 ]; //Array to store each ball in
void setup()
{
size( 400, 400 );
}
void draw()
{
background( 255 );
for( int i = 0; i < ballArray.length; i++ )
{
ballArray[ i ].display(); //Run each ball's display code every time step
}
}
class Ball
{
PVector location; //Vector to store this ball's location in
Ball( int x, int y )
{
location = new PVector( x, y );
ballArray = ( Ball[] ) append( ballArray, this ); //Add this ball to the array
}
void display()
{
fill( 0 );
ellipse( location.x, location.y ); //Display this ball at its location
}
}
void mousePressed()
{
new Ball( mouseX, mouseY ); //Create a new ball at the mouse location
}
And that would let me create as many instances as I like, anywhere I like.
I haven't the faintest clue how to make a comparable applet in Flash.
I've tried making a 'ball' class in a separate .as file, but it gives me an error about too many arguments. I also don't know how to draw a shape directly to the screen.
Can somebody whip up an equivalent of this in Flash so I have something to start from?
It'd also be fantastic if I could get some recommended reading for total flash noobs,
or developers moving from Java to Flash.

The following is a simple flash movie/app that creates a new instance of Ball and adds it to the stage when and where you click the mouse on the stage. Also upon each creation of a new instance of Ball, its appended to an array of Ball objects called _balls.
Main.as(document class):
package
{
import com.display.Ball;
import flash.display.Sprite;
import flash.events.MouseEvent;
public class Main extends Sprite
{
private var _balls:Array;
public function Main()
{
init();
}// end function
private function init():void
{
_balls = new Array();
stage.addEventListener(MouseEvent.CLICK, onStageMouseClick);
}// end function
private function onStageMouseClick(e:MouseEvent):void
{
createBall(e.stageX, e.stageY);
}// end function
private function createBall(p_x:Number, p_y:Number):void
{
var ball:Ball = new Ball(p_x, p_y);
addChild(ball);
_balls.push(ball);
}// end function
}// end class
}// end package
Ball.as:
package com.display
{
import flash.display.Sprite;
public class Ball extends Sprite
{
private var _radius:Number = 50;
private var _x:Number;
private var _y:Number;
private var _color:uint = 0xFF0000; // red
public function Ball(p_x:Number, p_y:Number)
{
_x = p_x;
_y = p_y;
init();
}// end function
public function init():void
{
draw();
}// end function
public function draw():void
{
this.graphics.beginFill(_color);
this.graphics.drawCircle(_x, _y, _radius);
this.graphics.endFill();
}// end function
}// end class
}// end package
I recommend reading the "ActionScript 3.0 Bible by Roger Braunstein" book for flash(as well as flex) "noobs". Also, even if you are experienced with ActionScript 3, it serves as a good reference book.
Also once you start to get a good grip on ActionScript 3, you may want to consider entering the realm of design patterns. To simplfy design patterns into a simple sentence it would probably be that they're "tools for coping with constant change in software design and development". I recommend reading "O'Reilly, ActionScript 3.0 Design Patterns by William Sanders & Chandima Cumaranatunge".

Check Colin Mook's Lost Actionscript Week End video tutorial , this will give you a good overview of Actionscript and enough understanding to apply your Processing knowledge to Flash. Bear in mind that in Processing a lot of the methods are hidden from you and you may have to write a lot more code in order to adapt Processing concepts to AS3.
http://tv.adobe.com/show/colin-moocks-lost-actionscript-weekend/

Related

Turns issue in java game [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I've created a simple game which a player plays against computer.
I've got an issue in the timing of the turns, the computer should be the first to make a move than the real player should make his move by clicking LeftChoice or RightChoice button.
Here's my problem at code:
public class GameForm extends javax.swing.JFrame {
/**
* Creates new form GameForm
*/
final int SIZE = 10;
int CurrentSize = 10;
int PC_SUM=0;
int HUMAN_SUM=0;
boolean PC_TURN = true;
int[] RandArr = new int[SIZE];
public GameForm() {
initComponents();
}
public void init(){
for(int i = 0 ; i<SIZE;i++){
RandArr[i] = (int)(Math.random()*100)+1;
}
jTextField3.setText("");
jTextField4.setText(Integer.toString(PC_SUM));
jTextField5.setText(Integer.toString(HUMAN_SUM));
}
public void HUMAN_updateLeft(){
HUMAN_SUM+=RandArr[0];
jTextField5.setText(Integer.toString(HUMAN_SUM));
jTextField1.setText(Arrays.toString(RandArr));
CurrentSize--;
int [] NewRand = new int[CurrentSize];
for(int i = 1 ; i<=CurrentSize;i++){
NewRand[i-1] = RandArr[i];
}
RandArr = NewRand;
jTextField2.setText(Arrays.toString(RandArr));
PC_TURN = true;
}
public void HUMAN_updateRight(){
HUMAN_SUM+=RandArr[CurrentSize-1];
jTextField5.setText(Integer.toString(HUMAN_SUM));
jTextField1.setText(Arrays.toString(RandArr));
CurrentSize--;
int [] NewRand = new int[CurrentSize];
for(int i = CurrentSize-1 ; i>=0;i--){
NewRand[i] = RandArr[i];
}
RandArr = NewRand;
jTextField2.setText(Arrays.toString(RandArr));
PC_TURN = true;
}
public static boolean WhoIsBigger(int[] arr){
int even=0,odd=0;
for(int i=0;i<arr.length;i+=2){
if(i%2==0){
even+=arr[i];
odd+=arr[i+1];
}
else{
odd+=arr[i];
even+=arr[i+1];
}
}
return even>odd;
}
public void PC_updateLeft(){
PC_SUM+=RandArr[0];
jTextField4.setText(Integer.toString(PC_SUM));
jTextField1.setText(Arrays.toString(RandArr));
CurrentSize--;
int [] NewRand = new int[CurrentSize];
for(int i = 1 ; i<=CurrentSize;i++){
NewRand[i-1] = RandArr[i];
}
RandArr = NewRand;
jTextField2.setText(Arrays.toString(RandArr));
}
public void PC_updateRight(){
PC_SUM+=RandArr[CurrentSize-1];
jTextField4.setText(Integer.toString(PC_SUM));
jTextField1.setText(Arrays.toString(RandArr));
CurrentSize--;
int [] NewRand = new int[CurrentSize];
for(int i = CurrentSize-1 ; i>=0;i--){
NewRand[i] = RandArr[i];
}
RandArr = NewRand;
jTextField2.setText(Arrays.toString(RandArr));
}
public void PC_TURN(){
if(WhoIsBigger(RandArr))
PC_updateLeft();
PC_updateRight();
}
public void FullGame(){
while(RandArr.length>0){
if(PC_TURN){
PC_TURN();
PC_TURN = false;
}
}
}
//start button listener
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
init();
jTextField2.setText(Arrays.toString(RandArr));
jTextField1.setText("-");
jButton1.setEnabled(false);
FullGame();
}
//left button listener
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
HUMAN_updateLeft();
}
//right button listener
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {
HUMAN_updateRight();
}
How can i know that the real player has made his move so it'll change PC_TURN to True and the game will move on?
Firstly, you should follow Java Naming Conventions when it comes to naming your variables. As it stands, PC_TURN looks as though it is a constant, although it is not a constant since you are changing it's value. So a more appropriate name would be pcTurn.
You also seem to have a method called PC_TURN() which I am assuming is the method which causes the computer to take it's turn and do something. So it would be better if this was named something descriptive like takePCTurn(). Notice the use of camelCase throughout. Capital letters at the start of a name should be reserved for classes and interfaces, not variables or methods.
The same goes for your method name
public void FullGame()
should be written as
public void fullGame()
Keeping to coding conventions like this make it easier for others to read and understand your code and keep everything neat and tidy. It's a good habit to get into. :)
I don't know where your left and right buttons are being declared or what you have named them, but you will need to add an event listener to each button which causes something to happen when they are clicked. I also am unsure about the purpose of RandArr.length > 0. You really don't need a loop here since this is an application with a GUI, it is never going to close unless you explicitly tell it to (e.g by clicking the close button). So I will just give you a generic solution.
You basically want the players turn to trigger the computer to take it's turn until some game over condition is met.
Example:
//Assuming this is called when the Start button is clicked
public void fullGame() {
takePCTurn();
}
public void takePCTurn() {
//Do PC's turn logic
//You might want to check if the Computer Won the game here
}
class PlayerTurnListener implements ActionListener() {
public void actionPerformed(ActionEvent e) {
//Do Player's turn logic
//You might want to check if the Player Won the game here
takePCTurn();
}
}
//We can create an instance of our listener and add it to both buttons
PlayerTurnListener playerTurnListener = new PlayerTurnListener();
leftButton.addActionListener(playerTurnListener);
rightButton.addActionListener(playerTurnListener);
So the first thing that happens is fullGame() is called by your Start button which then calls takePCTurn(); causing the computer to take it's turn. Now nothing will happen until the player clicks the left or right button. When they do this, the PlayerTurnListener's actionPerformed() method is called and you can do some logic in there and then takePCTurn(); will be called once again.
Rinse and repeat until gameover.
Hope that helps :)
You should attach a clickListener onto the left and right buttons. Then when the user clicks one that event will be fired. You should change PC_TURN to true there and re-run the loop if needed.
Example:
JButton yourButton = new JButton("Your Button");
yourButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
PC_TURN = true;
// extra code
}
});
If this is a Swing or other GUI then you will need to get rid of the while loop.
Remember that GUI programs are non-linear and are event-driven, and so rather than a restricting while loop which risks completely feezing your GUI, you would change the program's state depending on whose turn it is -- have a variable indicating whose turn it is -- and then change the behavior of the program based on the state.
If you need more specific help, then you're going to need to ask a much more complete question including one with enough code and explanation to allow us to understand your problem better (but not too much code).
Regarding the code you've posted:
Yes, definitely get rid of that while loop.
Your code is hard to understand, mainly because you're variable naming is poor. Rather than using variable names like jTextField1, use names that make logical sense, that make your code "self-debuggin", such as humanScoreField and computerScoreField, etc.
Also learn and follow standard Java naming practices including having all variables start with lower case letters, classes with upper case letters, use camelCase for all except for constants which are all upper-case.
Tell more about just what this code is supposed to be doing, what the buttons and the JTextfields represent, what behaviors you desire, etc...

JAVA Greenfoot Game Over / Win check on yCoordinate

I'm having this issue with my 2 checks for a frogger-style game.
So the Gameover check is a simple collision check on the frog object.
The next check does a getY coord check for checking if the frog object has hit the roof of the world ergo has beaten the game.
Now when the GameOver check is fulfilled there is no more object to do a getY check on. So it gives an error.
How can I bypass this ?
full code of the Frogger class:
public class Frogger extends Actor
{
public void act()
{
checkKeys();
hitEnemy();
atTop();
}
private void checkKeys()
{
if (Greenfoot.isKeyDown("up")) {
setLocation(getX(), getY()-3);
}
if (Greenfoot.isKeyDown("down")) {
setLocation(getX(), getY()+3);
}
if (Greenfoot.isKeyDown("left")) {
setLocation(getX()-3, getY());
}
if (Greenfoot.isKeyDown("right")) {
setLocation(getX()+3, getY());
}
}
public void hitEnemy()
{
Actor Enemy = getOneIntersectingObject(Enemy.class);
if(Enemy != null)
{
World myWorld = getWorld();
Gameover gameover = new Gameover();
myWorld.addObject(gameover, 300, 200);
myWorld.removeObject(this);
}
}
private void atTop()
{
if (getY() < 30)
{
World myWorld = getWorld();
Youwin youwin = new Youwin();
myWorld.addObject(youwin, 300, 200);
myWorld.removeObject(this);
}
}
}
Different approaches. When the game is over, you could just not do a getY() check anymore. Do not continue running the game, but rather to back to a main menu or something. the getY() method is irrelevant here. You could halt the program completely.
But your code looks weird. GameOver is an object? Rather than a simple method in your game. It does look like your code has a weird structure for a game. Anyway, when the game is over the 'gamelogic' loop should no longer be running, bur rather go to a menu.
Or you could keep the game running and do a null check. But reading your code, it seems like the whole structure is not that good. Is the aTop part of your Frog class? If so, it should exist for it to be called on. If you remove the Frog class from the world, you could do something like (but I do not see where the aTop method gets called)
if(myWorld.getFrog()!=null){
// Get method
}
Could you maybe share a bit more of your code? I think this should give you an idea though, there should be no more calls to the object when the object is removed, because the game ended and the normal game loop should no longer be running. And otherwise, nullchecks.

javafx animation looping

in c++ or c programming language, we know to change the cordinate we use gotoxy(x,y) and we can use looping and sleep to change the cordinate and making animation. like this;
for(x = 20; x < 25; x++){
gotoxy(x,20); cout << "*"
}
but my queston is how about in JAVAFX 2.0 programming? i'm using netbeans 7.2.
thanks for your any help.
Use the JavaFX Animation Package.
There are numerous examples in the JavaFX Animation Tutorial, as Andy pointed out in his comment.
And there is a cute example of a running horse animation loop.
The key is that you don't sleep the JavaFX application thread and you have to release control of the JavaFX thread back to the JavaFX system each time you update something and want it rendered. The JavaFX animation classes take care of these things for you so that you don't have to worry about it. If you just loop like you do in the sample code from your question, JavaFX will just render the scene once after your loop has completed and you will never see anything happen.
Here is a fairly boring example which uses a Timeline to emulate the c++ code in your question to move a dot a pixel every 400 milliseconds.
import java.util.Date;
import javafx.animation.*;
import javafx.application.Application;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
/** Simple JavaFX Animation Sample. */
public class AnimationSample extends Application {
private int x = 20;
private String status = "";
private final Circle dot = new Circle(20, 20, 3);
private final TimeCounter counter = new TimeCounter();
public static void main(String[] args) throws Exception { launch(args); }
#Override public void start(final Stage stage) throws Exception {
final Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, new EventHandler() {
#Override public void handle(Event event) {
refreshScene();
}
}),
new KeyFrame(Duration.millis(400))
);
timeline.setCycleCount(Timeline.INDEFINITE);
stage.setScene(new Scene(new Group(dot), 50, 50));
stage.show();
counter.reset();
timeline.play();
}
private void refreshScene() {
gotoxy(x, 20);
status = "*****".equals(status) ? "*" : status + "*";
System.out.println(String.format("%7d", counter.elapsed()) + " ms " + x + " " + status);
if (x == 24) {
x = 20;
} else {
x++;
}
}
private void gotoxy(int x, int y) {
dot.setCenterX(x);
dot.setCenterY(y);
}
class TimeCounter {
private long start = new Date().getTime();
void reset() { start = new Date().getTime(); }
long elapsed() { return new Date().getTime() - start; }
}
}
There are three different options in JavaFX, depending on your needs.
The most basic one is AnimationTimer. It's equivalent to Swing's Timer. It simply contains a handle method which is called on every frame, and passed current time as argument. You probably want some internal bookkeeping so that you do not do expensive calculations every time handle is called.
Transition has an interpolate(frac) method, which gets called with values of frac between 0.0 and 1.0. It's up to you to do all UI changes you want to, based on the frac value. Both Transition and Timeline extend Animation, so you can set stuff like cycle duration, whether the Transition is reversed at end, etc.
Timeline is the most complex one. You define arbitrary amount of KeyFrames (think of states) that contain wanted properties of different Nodes, and the Timeline will do all the work for you interpolating how to animate the change between the provided values. For example, you can give a keyframe where x property of a Node is 0, and another where it's 100, and Timeline will do the animating for you.
Have look at using a Timeline Animation. It is a key component of animation in JavaFX and
is used to establish when, and in what sequence, key parts of an animation occur.
Here is an example

repainting an applet from a swingworker used to compute triangles and circum-circles

I am trying to replicate the applet found here as a part of an exercise. The applet is using Fortune's algorithm to generate both; a Voronoi diagram and Delaunay triangulation. I am just interested in generating the Delaunay Triangulation in a plane and thus, would be using the incremental algorithms i.e. adding 1 point at a time. I intend to show the triangles being generated at every stage when a sample point is added.
I am using a SwingWorker class to create an instance of the Triangulate class which contains the algorithm. I am calling the triangulate method inside a for loop which iterates through the set of sample points when the start button on the GUI is clicked.
Here's the code for that:
JButton startButton = new JButton("Start");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
SwingWorker<List<Triangle>, Triangle> worker = new SwingWorker<List<Triangle>, Triangle>() {
#Override
protected List<Triangle> doInBackground() throws Exception {
Triangulate dt = new Triangulate(drawingPanel.pointsList());
dt.preTriangulate(); //Set-up a bounding triangle and obtain a random permutation of the points
List<PlanarPoint> pointsList = dt.pointsList();
for (int i = 0; i < pointsList.size(); i++) {
PlanarPoint sample = pointsList.get(i);
dt.triangulate(sample);
List<Triangle> list = dt.trianglesList(); //Obtaining the list of triangles at every stage. Good Idea??
for (int j = 0; j < list.size(); j++) {
publish(list.get(j));
}
Thread.sleep(500);
}
dt.removeTriangles(dt.trianglesList()); // Remove all the triangles containing bounding-triangle vertices
return dt.trianglesList();
}
protected void process(List<Triangle> triangles) {
for (Triangle triangle : triangles) {
g = drawingPanel.getGraphics();
PlanarPoint p1 = triangle.getVertex1();
PlanarPoint p2 = triangle.getVertex2();
PlanarPoint p3 = triangle.getVertex3();
g.drawLine((int) Math.ceil(p1.x), (int) Math.ceil(p1.y),
(int) Math.ceil(p2.x), (int) Math.ceil(p2.y));
g.drawLine((int) Math.ceil(p2.x),(int) Math.ceil(p2.y),
(int) Math.ceil(p3.x),(int) Math.ceil(p3.y));
g.drawLine((int) Math.ceil(p3.x),(int) Math.ceil(p3.y),
(int) Math.ceil(p1.x),(int) Math.ceil(p1.y));
}
}
};
worker.execute();
}
});
Here is the Triangulate class which computes a Delanuay Triangulation of a set of points:
public class Triangulate {
private List<PlanarPoint> pointsList;
private List<Triangle> triangleList;
private Triangle boundingTriangle;
private List<Edge> edgeList;
public Triangulate(List<PlanarPoint> pointsList) {
this.pointsList = pointsList;
this.triangleList = new ArrayList<Triangle>();
this.edgeList = new ArrayList<Edge>();
}
public List<Triangle> trianglesList() {
return triangleList;
}
public List<PlanarPoint> pointsList() {
return pointsList;
}
public void preTriangulate() {
boundingTriangle = getBoundingTriangle(pointsList);
triangleList.add(boundingTriangle);
randomPermutation(pointsList);
}
public void triangulate(PlanarPoint samplePoint) {
// A procedure implementing the Bowyer - Watson algorithm
// to calculate the DT of a set of points in a plane.
}
public void removeTriangles(List<Triangle> trianglesList) {
// A procedure to remove all triangles from the list sharing
// edges with the bounding-triangle
}
private Triangle getBoundingTriangle(List<PlanarPoint> pointsList) {
//Obtains a bounding-triangle for a set of points
}
public void randomPermutation(List<PlanarPoint> pointsList) {
//Obtains a random permutation of a set of points
}
}
I have 3 other classes
PlanarPoint - sub-class of Point2D.Double which implements Comparable to provide a y-co-ordinate based sorting
Triangle - A class which determines a circum-circle and circum-radius for the triangle and determines whether a point lies inside the circumcircle of the triangle
Edge - A class which represents Edge as the one having 2 PlanarPoints as its end-points.
DrawingPanel - A class which acts as the surface on which points are added at click events and drawn on the screen.
Now, here are a few concerns which I have
Is there a better way to show the triangles and possibly circum-circles by iterating over a set of points and then calling a function of the Triangulate class to get the existing circum-circles and triangles
Should all the drawing be restricted to the DrawingPanel class since in the code snippets above I am painting in the class which extends JApplet/JFrame and thus whenever the window is resized, the drawn triangles are lost? Is there a design pattern which I can follow?
Is the usage of SwingWorker over spawning another thread justified over here except for the fact that the time to compute the DT of a set of points is a time-consuming task?
If I have missed any details, please let me know
Thanks,
Chaitanya
Suggestions:
Don't use getGraphics() to get a Graphics object since the Graphics object obtained won't persist if any repaint is performed (something out of your control). Instead draw to a BufferedImage and have the JPanel or JComponent draw the BufferedImage in its paintComponent override, or add your image data to a Collection of some sort, and have the paintComponent override method iterate through the Collection using the information to draw your images.
Don't draw directly in a top level window such as a JFrame or JApplet, but instead in a component that derives from JComponent, often either JComponent itself or JPanel.
Read the Swing graphics tutorials as they will explain all of this and more.
SwingWorker is fully justified since you want to create a thread that is background to a Swing application yet interacts with the Swing application -- the very situation that SwingWorkers were created for.

Methods and decomposition

I'm just starting learning Java after a few years of HTML/CSS coding so hopefully I'm not asking a old or stupid question here but any help explaining this problem would be very much appreciated.
I'm currently working through the Stanford CS106A online material and I've reached week 6, Assignment 2, Question 3 (http://see.stanford.edu/materials/icspmcs106a/13-assignment-2-simple-java.pdf).
As you can see it requires the placement of various objects on the screen to create the Graphics Hierarchy, as described. My plan was to use the centre coordinates to relatively place all the objects on the screen. However I've hit a problem that I can't seem to find an answer to. The course describes how Method Decomposition should allow each method to handle one problem (Single Responsibility Principle, I believe) so I have written the first part of my code as such:
//Import any libraries
import acm.program.*;
import acm.graphics.*;
public class GraphicsHierarchy extends GraphicsProgram {
//Define constants
static final int BOX_WIDTH = 200;
static final int BOX_HEIGHT = 75;
public void run() {
placeGRect();
}
//Find centre x & y
double centre_x = getWidth() / 2; //check this
double centre_y = getHeight() * 0.5;//and this
//placeGRect method
public void placeGRect() {
for (int count = 0; count < 4; count++) {
GRect box = new GRect (BOX_WIDTH, BOX_HEIGHT);
add(box);
switch (count) {
case 0:
box.setLocation(centre_x, 75);
break;
case 1:
box.setLocation((centre_x * 0.5), 250);
break;
case 2:
box.setLocation(centre_x, 250);
break;
case 3:
box.setLocation((centre_x * 1.5), 250);
break;
}
}
}
}
However this doesn't work due to the centre_x & centre_y producing zero values. I discovered this by changing the program to a ConsoleProgram and having the getWidth & getHeight lines inside the run() method (and println their values on screen), which then produced the required values but didn't pass them to the GRect method (so still didn't work). However if I have the getWidth/getHeight lines listed out of the run() then they don't produce any values for relative positioning.
My question is given that each method should handle one task and (as much as possible) methods should be defined out of the run() method, then how I can I get the getWidth/getHeight values to the placeGRect() method without having one big block of code within the run() method. Which I understand is bad practise.
I'm not after any code to solve this, I really need to understand the principles of this so I can write effective code in the future. I prefer understanding to parrot-fashion code copying.
Thanks in advance for any help.
In your specific example:
You have declared centre_x and centre_y as instance variables. When your program first creates an instance of GraphicsHierarchy the order of object creation is as such:
ClassLoader loads the class... static variables (BOX_WIDTH,BOX_HEIGHT) are assigned specified values;
Space is allocated on the heap for an instance of GraphicsHierarchy (enough space to hold the instance variables - a double for centre_x and a double for centre_y- including space for base class instance variables)
Instance variables are set to default values: centre_x = 0, centre_y = 0
The GraphicsHierarchy default constructor is called (which does nothing other than call the base class constructor - GraphicsProgram).
The base class will go through steps 1-4 and when it's finished execution returns to GraphicsHiearchy which now evaluates explicit instance variable initializers before executing any remaining constructor statements (which in the case of the default constructor, there are none).
(additional reference on this process http://java.dzone.com/articles/java-object-initialization)
Having said all of that, it would appear that when your class GraphicsHierarchy gets to step 5 and tries to assign values to centre_x and centre_y, the subsystem that getWidth and getHeight rely upon is not ready (i.e. a window or canvas has not been created yet, so the methods return 0). But when you moved your assignments inside run and getWidth/getHeight returned values, that would imply whatever method is calling run has first gone through the necessary window creation steps.
Etienne de Martel's suggestion is fine. It delays assignment of your centre values until right before they are needed. If you'd rather, you could create an init method and move the assignments inside the init method, and then call init as the first step of run
private void init() {
centre_x = getWidth / 2;
centre_y = getHeight * 0.5;
}
public void run() {
init();
placeGRect();
}
This is nearly the same thing as Martel's suggestion, although if you find later you have other initialization code that needs to happen, you can throw it in the same place.
As for crafting flexible code you might think about renaming placeGRect to placeGRects and passing in array of points (or Collection if you prefer) placeGRects(Point[] points)
(you can use Java.awt.Point or define your own Point class)
In this way, your placeGRects method is simplified. It no longer decides how many boxes to render (the array that is passed in does). It also doesn't determine where those new boxes are located (again the array of Point objects do). It simply loops through the size of the array, makes a new box, adds it, and sets the location.
private Point[] boxPoints;
public void run() {
init();
placeGRects(boxPoints);
}
public void placeGRects(Point[] points) {
for(int i=0;i<points.length;i++) {
GRect b = new GRect(BOX_WIDTH,BOX_HEIGHT);
add(b);
b.setLocation(points[i].x,points[i].y);
}
}
And you can put your Point array initialization inside your new init() method.
private void init() {
centre_x = getWidth / 2;
centre_y = getHeight * 0.5;
boxPoints = {new Point(centre_x, 75),new Point(centre_x * 0.5, 250)};
}
It makes your code easier to understand and modify when needed.
Perhaps I don't understand your question, but why not pass them as parameters?
protected void placeGRect(double centre_x, double centre_y) {
// ...
}
You can then call placeGRect like so:
public void run() {
placeGRect(getWidth() / 2, getHeight() * 0.5);
}
Very nice question! How to compose your methods is a matter of intuition rather than strict guidelines.
Certainly, methods should be focused on doing one thing and one thing only. Firstly, having short methods (even one-liners!) improves the understandability of the code. As a very rough example, think of this:
if (DateUtils.before(ticket.getExpirationDate(), new Date())) {
accept(ticket);
}
and then this
if (isNotExpired(ticket)) {
accept(ticket);
}
...
private boolean isNotExpired(Ticket t) {
return DateUtils.before(t.getExpirationDate(), now());
}
private Date now() {
return (new Date());
}
Pay attention to how the introduction of one line methods isNotExpired() and now() significantly improved your undestanding of what the code does.
Here's another example, this time that has to do with constructing objects:
Loan l1 = new Loan(15000, 36, f7.2, 2.5);
Loan l2 = new Loan(15000, 36, f7.2);
vs.
Loan l1 = Loan.newSubsidizedLoan(15000, 36, f7.2, 2.5);
Loan l2 = Loan.newNormalLoan(15000, 36, f7.2);
Note in this example how wrapping the constructors in two different methods significantly improves the documentation of code (without even needing to write comments);
If you are interested on the general topic of coding style, you should read this book.
Cheers
L.
Your code doesn't seem to include the getWidth() and getHeight() methods. Also, the following piece of code is totally wrong as a placement and should be placed in a constructor:
double centre_x = getWidth() / 2; //check this
double centre_y = getHeight() * 0.5;//and this
Should become
private double centre_x;
private double centre_y;
GraphicsHierarchy(){
centre_x = GraphicsHierarchy.BOX_WIDTH / 2;
centre_y = GraphicsHierarchy.BOX_HEIGHT * 0.5;
}
This code will at least compile, but consider the solution described below, which is even better.
Considering that you have defined BOX_WIDTH and BOX_HEIGHT as static variables, you can always find centre_x and centre_y. Therefore, you don't even need to define BOX_WIDTH and BOX_HEIGHT
You can define your class like this:
//Import any libraries
import acm.program.*;
import acm.graphics.*;
public class GraphicsHierarchy extends GraphicsProgram {
public void run() {
placeGRect();
}
//Define constants
public static final double CENTRE_X= 100.00;
public static final double CENTRE_Y = 37.50;
//placeGRect method
public void placeGRect() {
for (int count = 0; count < 4; count++) {
GRect box = new GRect (200, 75);
add(box);
switch (count) {
case 0:
box.setLocation(GraphicsHierarchy.CENTRE_X, 75);
break;
case 1:
box.setLocation((GraphicsHierarchy.CENTRE_X * 0.5), 250);
break;
case 2:
box.setLocation(GraphicsHierarchy.CENTRE_X, 250);
break;
case 3:
box.setLocation((GraphicsHierarchy.CENTRE_X * 1.5), 250);
break;
}
}
}
}
In my opinion, you can go even further by eliminating all computations and replace such stuff
GraphicsHierarchy.CENTRE_X * 1.5
with
150
Come on, have it easy on your Virtual Machine! Your class uses a whole load of static information, so there is no need for so much computation. But having a BOX_WIDTH and BOX_HEIGHT is completely useless as constants, as they are used only internally and only on one place. Calculating centre_x and centre_y out of the BOX_WIDTH and BOX_HEIGHT is also useless, as as they are final, you can easily do the computation yourself and reduce unnecessary creation of variables.
In addition, you don't use the centre_y value anywhere, so you should ditch it.
To further add some helpful advice, a decent IDE, like NetBeans, Eclipse, or IntellIJIDEA should have code completion and syntax highlighting and will help you immensely in becoming a better (or more knowledgable, which is even better) programmer.

Categories

Resources