Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Update: Just to specify, depending on how I change the rules I can set it so within a couple of generations all cells are either permanently alive or dead. I have checked this by echoing statements to console. HOWEVER, this doesn't reflect in the GUI which shows all cells as always the same color.
I am trying to implement a simple Cellular Automaton to replicate the game of life. This uses the MASON library. My three classes:
Cell.java
package sim.app.gol;
import sim.engine.SimState;
import sim.engine.Steppable;
import sim.field.grid.IntGrid2D;
import sim.util.IntBag;
public class Cell implements Steppable {
public IntGrid2D grid = new IntGrid2D(0,0);
public void step(SimState state) {
Matrix matrix = (Matrix) state;
grid.setTo(matrix.matrix);
for(int x = 0; x < grid.getWidth(); x++) {
for(int y = 0; y < grid.getHeight(); y++) {
IntBag nei = grid.getMooreNeighbors(x, y, 2, 0, false, new IntBag(), new IntBag(), new IntBag());
int count = 0;
for(int i = 0; i < nei.size(); i++) {
count += nei.get(i);
}
int currentState = grid.get(x, y);
if(currentState == 0) {
if(count > 3)
matrix.matrix.set(x, y, 1);
} else if(currentState == 1) {
matrix.matrix.set(x,y,0);
}
}
}
}
}
Matrix.java
package sim.app.gol;
import ec.util.MersenneTwisterFast;
import sim.engine.SimState;
import sim.field.grid.IntGrid2D;
public class Matrix extends SimState {
public final int HEIGHT = 10;
public final int WIDTH = 10;
public IntGrid2D matrix = new IntGrid2D(HEIGHT, WIDTH);
public final int NUM_CELLS = 80;
public Matrix(long seed) {
super(seed);
}
public void start() {
super.start();
// Utils for random number generator
MersenneTwisterFast g = new MersenneTwisterFast();
// We set everything to 0, no cells are active
matrix.setTo(0);
// Populating
for(int i = 0; i < NUM_CELLS; i++) {
int x = 0;
int y = 0;
// We don't want to mark as 'active' a cell that is already active
do {
x = g.nextInt(WIDTH);
y = g.nextInt(HEIGHT);
} while(matrix.get(x, y) == 1);
matrix.set(x, y, 1);
}
schedule.scheduleRepeating(new Cell());
}
public static void main(String[] args) {
doLoop(Matrix.class, args);
System.exit(0);
}
}
MatrixWithUI.java
package sim.app.gol;
import java.awt.Color;
import javax.swing.JFrame;
import sim.app.students.Students;
import sim.display.Console;
import sim.display.Controller;
import sim.display.Display2D;
import sim.display.GUIState;
import sim.engine.SimState;
import sim.portrayal.continuous.ContinuousPortrayal2D;
import sim.portrayal.grid.ObjectGridPortrayal2D;
import sim.portrayal.grid.ValueGridPortrayal2D;
import sim.portrayal.simple.OvalPortrayal2D;
public class MatrixWithUI extends GUIState {
public Display2D display;
public JFrame displayFrame;
public ValueGridPortrayal2D matrixPortrayal = new ValueGridPortrayal2D();
public static void main(String[] args) {
MatrixWithUI mwu = new MatrixWithUI();
Console c = new Console(mwu);
c.setVisible(true);
}
public void start() {
super.start();
setupPortrayals();
}
public void load(SimState state) {
super.load(state);
setupPortrayals();
}
public void setupPortrayals() {
Matrix matrix = (Matrix) state;
matrixPortrayal.setField(matrix.matrix);
matrixPortrayal.setPortrayalForAll(new OvalPortrayal2D());
display.reset();
display.setBackdrop(Color.white);
display.repaint();
}
public void init(Controller c) {
super.init(c);
display = new Display2D(600,600,this);
display.setClipping(true);
displayFrame = display.createFrame();
displayFrame.setTitle("Schoolyard Display");
c.registerFrame(displayFrame);
displayFrame.setVisible(true);
display.attach(matrixPortrayal, "Yard");
}
public void quit() {
super.quit();
if (displayFrame != null) displayFrame.dispose();
displayFrame = null;
display = null;
}
public MatrixWithUI() {
super(new Matrix (System.currentTimeMillis()));
}
public MatrixWithUI(SimState state) {
super(state);
}
public static String getName() {
return "Student Schoolyard Cliques";
}
}
However, for some reason all cells are continuously set to 0 (or off). Any thoughts?
Note: this is a tentative answer as I have no way of verifying it at the moment.
First, let's look at the documentation of ValueGridPortrayal2D. It says:
Like other FieldPortrayal2Ds, this class uses an underlying SimplePortrayal2D to draw each separate element in the grid. A default SimplePortrayal2D is provided which draws squares. In the default, the color for the square is determined by looking up the value of the square in a user-provided color-table, or if there is none, by interpolating it between two user-provided colors. See the setColorTable() and setLevels() methods.
So, if you settle for squares rather than ovals, you can drop this line:
matrixPortrayal.setPortrayalForAll(new OvalPortrayal2D());
And instead, add:
java.awt.Color[] colorTable = new java.awt.Color[2];
colorTable[0] = new java.awt.Color(1.0F,0.0F,0.0F,0.0F);
colorTable[1] = new java.awt.Color(1.0F,0.0F,0.0F,1.0F);
matrixPortrayal.setMap( new SimpleColorMap(colorTable) );
This should give you white squares (transparent on a white backdrop) for 0, and red squares for 1.
If you want to draw ovals, this default implementation of a SimplePortrayal2D that uses a map is not available. The documentation goes further to say:
You can also provide your own custom SimplePortrayal2D (use setPortrayalForAll(...) ) to draw elements as you see fit rather than as rectangles. Your SimplePortrayal2D should expect objects passed to its draw method to be of type MutableDouble.
So we need to override the draw() method and treat the passed object - the cell value - as a MutableDouble (by which I assume they mean the one from org.apache.commons.lang):
matrixPortrayal.setPortrayalForAll(new OvalPortrayal2D() {
public void draw(Object object, Graphics2D graphics, DrawInfo2D info) {
MutableDouble valueObj = (MutableDouble)object;
if ( valueObj.intValue() == 0 ) {
paint = new java.awt.Color(1.0F,0.0F,0.0F,0.0F);
} else {
paint = new java.awt.Color(1.0F,0.0F,0.0F,1.0F);
}
filled = true;
super.draw(object, graphics, info);
}
});
So we have created an anonymous subclass of OvalPortrayal2D. It inherits the fields paint, filled and scale from AbstractShapePortrayal2D. So we override paint (java.awt.Paint, which java.awt.Color extends) with the color we need for the particular value, and make sure the oval is filled.
Related
Why is only one rectangle being painted here even though I call the repaint() method multiple times in my for() loop? Additionally I want to display 8 rectangles per row and 8 rectangles per column with 2 pixels space in between. Any ideas or help?
package PROG2;
import java.awt.*;
import java.util.*;
import javax.swing.*;
class Model {
int m_width;
int m_height;
int m_x1 = 50;
int m_y1 = 50; //Information about the model
int m_x2 = 100;
int m_y2 = 30;
int counter = 0; //Assisting variable
Model(int width,int height) {
m_width = width;
m_height = height;
}
void math() {
counter = counter + 2;
counter = counter + m_x2;
m_x1 = counter;
}
}
class View extends JComponent {
private Model m_Mod;
View(Model mod) {
m_Mod = mod;
}
#Override
protected void paintComponent(Graphics g) {
//super.paintComponent(g);
g.setColor(Color.green);
g.drawRect(m_Mod.m_x1,m_Mod.m_y1,
m_Mod.m_x2,m_Mod.m_y2);
g.fillRect(m_Mod.m_x1,m_Mod.m_y1,
m_Mod.m_x2,m_Mod.m_y2);
}
}
class Controller {
private Model m_Mod;
private View m_View;
Controller(){
m_Mod = new Model(500,500);
m_View = new View(m_Mod);
JFrame frame = new JFrame();
frame.add(m_View);
frame.setSize(m_Mod.m_width,m_Mod.m_height);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Graphics g = frame.getGraphics();
}
void simulate(int right, int down){
for( int i = 0; i < right; i++) {
m_Mod.math();
m_View.repaint();
}
}
}
class Übung2{
public static void main(String[] args) throws Exception {
Controller c = new Controller();
c.simulate(8, 8);
}
}
Even when you call repaint() multiple times, the actual drawing will take place only once at a later time (until swing will trigger a repaint again). At that time, the content of the paintComponent() method is executed. The code you have in your method only draws one rectangle (drawRect()) and one filled rectangle (fillRect()) and that's it, nothing more. So you don't get more than what you wrote in your method.
You can use arrays (or lists) to store the multiple XY coordinates of your rectangles and then iterate over the array/list to draw multiple rectangles while inside the single call of paintComponent(). The code can look like this:
#Override
protected void paintComponent(Graphics g) {
//super.paintComponent(g);
g.setColor(Color.green);
foreach (RectModel rect: m_Mod.getRectangles()) {
g.drawRect(rect.x1, rect.y1, rect.x2, rect.y2);
}
}
This assumes you have such a class RectModel which holds the data of one rectangle (x1, y1, x2, y2) and that you have a method m_Mod.getRectangles() which returns an array/list of RectModel instances. When you execute the simulate() method in your controller, you will calculate all the rectangles you want to draw and save them in the this.rectangles array/list of the Model class. After that the paintComponent() method fill use that array/list and draws the rectangles.
I am trying to make a simple game with Java swing/awt.
I am have issue with lagging while printing and moving images on the screen.
Here is my code below:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.File;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.*;
public class StarDef extends JFrame implements Runnable, KeyListener{
private BufferedImage back;
private boolean start = false, end = false;
public int w = 1500, h = 800, commandx = 200, commandy = 100, ground = 500, mineral = 100;
private int mineralx = 0, mineraly = commandy + 104;
private int dronecnt = 0;
private ArrayList<Drone> DrList = null;
private ArrayList<Enemy> EnList = null;
private ArrayList<Building> BuildList = null;
private ArrayList<Allies> AlyList= null;
public Image imagearr[] = new Image[10];
private boolean makedrone = false, NeedMinerals = false;
public int picnum = 1;
private int OrderBuild = 0;
public static void main(String[] args){
Thread t = new Thread(new StarDef());
t.start();
}
public StarDef(){
back = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
DrList = new ArrayList<>();
BuildList = new ArrayList<>();
EnList = new ArrayList<>();
AlyList = new ArrayList<>();
this.addKeyListener(this);
this.setSize(w,h);
this.setTitle("Starcraft");
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
try {
imagearr[0] = ImageIO.read(new File("Char/Command.png"));
imagearr[1] = ImageIO.read(new File("Char/droneleft.png"));
imagearr[2] = ImageIO.read(new File("Char/droneright.png"));
imagearr[3] = ImageIO.read(new File("Char/Mineral.png"));
imagearr[4] = ImageIO.read(new File("Char/barracks.png"));
} catch (Exception e){
e.printStackTrace();
}
}
public void initGame(){
DrList.clear();
mineral = 100;
}
public void draw(){
Graphics gs = back.getGraphics();
gs.setColor(Color.white);
gs.fillRect(0,0,w,h);
gs.setColor(Color.DARK_GRAY);
gs.fillRect(0,ground,w,200);
if (!end) {
gs.drawImage(imagearr[0], commandx, commandy, null); // First Image-Command Center
gs.drawImage(imagearr[3], mineralx,mineraly,null); // Second Image-Mineral
for (int i = 0; i < DrList.size(); i++) { //Printing Drones
Drone m = DrList.get(i);
gs.drawImage(imagearr[m.state], m.x, m.y, null); //Drawing Drones
m.moveDr(); // Moving the Drone
}
for (int i = 0; i < BuildList.size(); i++){ //Printing Building
Building bd = BuildList.get(i);
if(bd.buildingtype == 'R'){
gs.drawImage(imagearr[4], bd.x, bd.y, null); // Drawing Building-Problem starts..?
}
}
gs.drawImage(imagearr[0], commandx, commandy, null);
}
gs.setColor(Color.black);
gs.drawString("mineral : " + mineral, 10,50);
gs.drawString("Drones : " + DrList.size(), 10, 70);
Graphics ge = this.getGraphics();
ge.drawImage(back, 0,0,w,h,this);
}
public void run(){
try{
int timer = 10;
while (true){
Thread.sleep(timer);
if(start){
if (makedrone) {
makedrone();
}
if (OrderBuild>0){
makeBuilding(OrderBuild);
}
}
draw();
}
} catch (Exception e){
e.printStackTrace();
}
}
public void makeBuilding(int buildingnumber){
int bdx, bdy;
char BuildingType;
if(buildingnumber == 1){
bdx = 500;
bdy = 100;
BuildingType = 'R';
Building barracks = new Building(this, bdx, bdy, BuildingType);
BuildList.add(barracks);
}
}
public void makedrone() {
if (mineral >= 50) {
int dronex = commandx;
int droney = commandy+129;
Drone dr = new Drone(this ,dronex, droney);
DrList.add(dr);
dronecnt++;
mineral -= 50;
makedrone = false;
} else if (mineral < 50) {
NeedMinerals = true;
makedrone = false;
}
}
public void keyPressed(KeyEvent ke){
switch (ke.getKeyCode()){
case KeyEvent.VK_ENTER:
start = true;
end = false;
break;
case KeyEvent.VK_D:
makedrone = true;
break;
case KeyEvent.VK_R:
OrderBuild = 1;
break;
}
}
public void keyReleased(KeyEvent ke){
switch ((ke.getKeyCode())){
}
}
public void keyTyped(KeyEvent ke) {
}
}
When you compile the code, the first few stationary images appear fine.
After moving images(Drones) appear nicely, but when you summon the next stationary image(Building), heavy lag starts to appear and the speed of the moving drones decrease visibly.
The building is about 300*150 pixels and the drones are 40*30 pixels.
What is the cause of this problem? Is this because of the code(the way of summoning the image), or the picture's size, or the computer(I am using a notebook(LG Gram 14in)).?
Start by not using Graphics ge = this.getGraphics();.
Because you're also using your own Thread, you're running the risk of thread race conditions which could result in dirty reads/ paints.
Start by understanding how Swing painting actually works and work within the API functionality.
Start by having a look at Performing Custom Painting, Painting in AWT and Swing and Concurrency in Swing
KeyListener is also a poor choice for monitor key input and you should be using the Key Bindings API - see How to use key bindings for more details.
Adding content to the ArrayList can cause the ArrayList to go through a growth cycle, which can consume time and force a longer GC cycle. Consider seeding the ArrayList with initial capacity, it will help reduce the interval between growth cycles.
Focus on separating the "update" logic from the "paint" logic, it can help you find performance issues
You could also have a look at
java what is heavier: Canvas or paintComponent()?
Swing animation running extremely slow
Rotating multiple images causing flickering. Java Graphics2D
Which demonstrate a verity of techniques for improving performance of rendering in Swing.
If these still are't getting your to the level you want, then you will want to explore using a BufferStrategy
Better draw in JPanel and use repaint() method to update your JPanel
How can this code be broken down to follow the principles of single responsibility principle? Even though I understand the SOLID principles and have read through many materials especially Uncle Bob's articles on SOLID principles I have unfortunately been unable to split the following code to two different classes to follow Single Responsibility Principle. I would highly appreciate help from StackOverflow
/** The only subclass the fully utilizes the
Entity superclass (no other class requires
movement in a tile based map).
Contains all the gameplay associated with
the Player.**/
package com.neet.DiamondHunter.Entity;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import com.neet.DiamondHunter.Manager.Content;
import com.neet.DiamondHunter.Manager.JukeBox;
import com.neet.DiamondHunter.TileMap.TileMap;
public class Player extends Entity {
// sprites
private BufferedImage[] downSprites;
private BufferedImage[] leftSprites;
private BufferedImage[] rightSprites;
private BufferedImage[] upSprites;
private BufferedImage[] downBoatSprites;
private BufferedImage[] leftBoatSprites;
private BufferedImage[] rightBoatSprites;
private BufferedImage[] upBoatSprites;
// animation
private final int DOWN = 0;
private final int LEFT = 1;
private final int RIGHT = 2;
private final int UP = 3;
private final int DOWNBOAT = 4;
private final int LEFTBOAT = 5;
private final int RIGHTBOAT = 6;
private final int UPBOAT = 7;
// gameplay
private int numDiamonds;
private int totalDiamonds;
private boolean hasBoat;
private boolean hasAxe;
private boolean onWater;
private long ticks;
// player status
private int healthPoints;
private boolean invincible;
private boolean powerUp;
private boolean speedUp;
public Player(TileMap tm) {
super(tm);
width = 16;
height = 16;
cwidth = 12;
cheight = 12;
moveSpeed = 2;
numDiamonds = 0;
downSprites = Content.PLAYER[0];
leftSprites = Content.PLAYER[1];
rightSprites = Content.PLAYER[2];
upSprites = Content.PLAYER[3];
downBoatSprites = Content.PLAYER[4];
leftBoatSprites = Content.PLAYER[5];
rightBoatSprites = Content.PLAYER[6];
upBoatSprites = Content.PLAYER[7];
animation.setFrames(downSprites);
animation.setDelay(10);
}
private void setAnimation(int i, BufferedImage[] bi, int d) {
setAnimation(i, bi, d, false);
}
private void setAnimation(int i, BufferedImage[] bi, int d, boolean slowMotion) {
currentAnimation = i;
animation.setFrames(bi);
animation.setDelay(d);
slowMotion = true;
}
public void collectedDiamond() { numDiamonds++; }
public int numDiamonds() { return numDiamonds; }
public int getTotalDiamonds() { return totalDiamonds; }
public void setTotalDiamonds(int i) { totalDiamonds = i; }
public int getx() { return x; }
public int gety() { return y; }
public int getRow() { return rowTile; }
public int getCol() { return colTile; }
public void gotBoat() { hasBoat = true; tileMap.replace(22, 4); }
public void gotAxe() { hasAxe = true; }
public boolean hasBoat() { return hasBoat; }
public boolean hasAxe() { return hasAxe; }
public int getHealthPoints() { return healthPoints; }
// Used to update time.
public long getTicks() { return ticks; }
// Keyboard input. Moves the player.
public void setDown() {
super.setDown();
}
public void setLeft() {
super.setLeft();
}
public void setRight() {
super.setRight();
}
public void setUp() {
super.setUp();
}
// Keyboard input.
// If Player has axe, dead trees in front
// of the Player will be chopped down.
public void setAction() {
final boolean pressUPKEY = currentAnimation == UP && tileMap.getIndex(rowTile - 1, colTile) == 21;
final boolean pressDOWNKEY = currentAnimation == DOWN && tileMap.getIndex(rowTile + 1, colTile) == 21;
final boolean pressLEFTKEY = currentAnimation == LEFT && tileMap.getIndex(rowTile, colTile - 1) == 21;
final boolean pressRIGHTKEY = currentAnimation == RIGHT && tileMap.getIndex(rowTile, colTile + 1) == 21;
if(hasAxe) {
if(pressUPKEY) {
tileMap.setTile(rowTile - 1, colTile, 1);
}
if(pressDOWNKEY) {
tileMap.setTile(rowTile + 1, colTile, 1);
}
if(pressLEFTKEY) {
tileMap.setTile(rowTile, colTile - 1, 1);
}
if(pressRIGHTKEY) {
tileMap.setTile(rowTile, colTile + 1, 1);
}
JukeBox.play("tilechange");
}
}
public void update() {
ticks++;
boolean current = onWater;
onWater = CheckIfOnWater();
//if going from land to water
if(!current && onWater){
JukeBox.play("splash");
}
// set animation
setAnimationDown();
setAnimationLeft();
setAnimationRight();
setAnimationUp();
// update position
super.update();
}
public void setAnimationUp() {
if(up) {
if(onWater && currentAnimation != UPBOAT) {
setAnimation(UPBOAT, upBoatSprites, 10);
}
else if(!onWater && currentAnimation != UP) {
setAnimation(UP, upSprites, 10);
}
}
}
public void setAnimationRight() {
if(right) {
if(onWater && currentAnimation != RIGHTBOAT) {
setAnimation(RIGHTBOAT, rightBoatSprites, 10);
}
else if(!onWater && currentAnimation != RIGHT) {
setAnimation(RIGHT, rightSprites, 10);
}
}
}
public void setAnimationLeft() {
if(left) {
if(onWater && currentAnimation != LEFTBOAT) {
setAnimation(LEFTBOAT, leftBoatSprites, 10);
}
else if(!onWater && currentAnimation != LEFT) {
setAnimation(LEFT, leftSprites, 10);
}
}
}
public void setAnimationDown() {
if(down) {
if(onWater && currentAnimation != DOWNBOAT) {
setAnimation(DOWNBOAT, downBoatSprites, 10);
}
else if(!onWater && currentAnimation != DOWN) {
setAnimation(DOWN, downSprites, 10);
}
}
}
public boolean CheckIfOnWater(){
int index = tileMap.getIndex(ydest / tileSize, xdest / tileSize);
if(index == 4) {
return true;
}
else {
return false;
}
}
// Draw Player.
public void draw(Graphics2D g)
{
super.draw(g);
}
}
Try to implement your components in a Model View Controller style, for example move all the code related to the update the view in a package yourapp.view for example, and move the code of your current class Player into a new class for example, GameBoard or GameView or whaterver, where the single responsability of this class is updating the model representations drawing the animations/images etc., in the gameboard screen. Another class for example, PlayerMovement and move all the code related to de keyboard events, currenly in your Player class, where the responsability of this class is catching the keys that makes the player move.
Move all the code related with game orders and desitions and move in another package yourapp.controller or actions or whatever, and create new classes for example PlayerController, GameController or whatever, where the single responsability of this class is receive the player requests to update the game models state, addressing commands and saying to the model classes be updated and saying to de view classes that gets the new model state every time that the model changes; for example when the player has a new location in the game board, or the location of some missil or some character die etc.
Put your model classes for example in other package for example yourapp.character or actors or whatever, and move the code related to the model state creating new classes that represent the game characters or actors or live elements that defining the behabior or roles of your game. For example the player or a Ship or a Cannon etc. This classes their responsability is only define the game character and their characteristis and behavior por example the location in the gameboard, their weapons, their powers, if is live or dead etc., and other info neded about their role into the game.
Try to identify and apply in a second stage, GoF pattern this can help you to refactor your code and make it more acurate to SOLID principles.
Another of thinking about SRP is each unit should have a Single Reason for Change.
Take your class, what are the reasons one might change it in future:
The sprites change.
The animation changes.
The gameplay changes.
The player status logic changes.
Each of those you have organised fields for, so you spotted them yourself. Now just go one step further and create classes for each of those. So that you can change, for example, animation without touching code that affects gameplay. This:
Makes changes safer (fewer side effects in the absence of a good test suite)
Makes it easier to work on, you need to read less code, just the part you're interested in
Makes it easier for your team to review changes (they will know you haven't affected gameplay while changing animation, for example)
Makes it easier for a team to work on different parts of the system with less chance of merge conflicts
Makes it easy to swap out one component for another implementation, you could, for example, re-skin your game by replacing the sprites component with another
I have started developing Tetris Game. Everything is working fine but how to retain rectangles at the bottom?
This is the Comp1 class in which the random shape is retrieved and move down with the timer
package buildblock;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import buildblock.tetris;
public class Comp1 extends JPanel implements ActionListener {
int curx=10;
int cury=30;
int nx=0;
int ny=0;
int p=1;
Timer t;
boolean EndofLine=false;
JLabel l1=new JLabel("");
int value=0;
int coords[][][]=new int[3][3][2];
int shape[][][][]={
{{{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0}},{{0,0},{0,0},{0,0}}},
{{{0,0},{100,20},{0,0}},{{0,0},{100,40},{0,0}},{{80,60},{100,60},{0,0}}},
{{{0,0},{100,20},{0,0}},{{80,40},{100,40},{120,40}},{{0,0},{0,0},{0,0}}},
{{{0,0},{100,20},{0,0}},{{0,0},{100,40},{0,0}},{{0,0},{100,60},{0,0}}},
{{{80,20},{100,20},{0,0}},{{0,0},{100,40},{0,0}},{{0,0},{100,60},{0,0}}},
{{{0,0},{100,20},{0,0}},{{80,40},{100,40},{0,0}},{{80,60},{0,0},{0,0}}},
{{{80,20},{0,0},{0,0}},{{80,40},{100,40},{0,0}},{{0,0},{100,60},{0,0}}},
{{{80,20},{100,20},{0,0}},{{80,40},{100,40},{0,0}},{{0,0},{0,0},{0,0}}},
};
Comp1(tetris Parent)
{
setVisible(true);
setSize(400,900);
curx=(400-curx)/2;
setLayout(new BorderLayout());
timer();
}
public void getShape(int a)
{
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
for(int k=0;k<2;k++)
{
coords[i][j][k]=shape[a][i][j][k];
repaint();
}
}
}
}
public void paint(Graphics g)
{
super.paint(g);
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
for(int k=0;k<2;k++)
{
if(coords[i][j][k]!=0)
{
if(k==0)
{
curx=coords[i][j][k]+nx;
}
else
{
cury=coords[i][j][k]+ny;
drawRec(g,curx,cury,20,20);
}
}
}
}
}
}
public void drawRec(Graphics g,int newx,int newy,int w,int h)
{
g.drawRect(newx, newy, 20, 20);
g.drawLine(curx+1,cury+20-1,curx+20-1,cury+20-1);
}
public void timer()
{
t=new Timer(150,this);
t.start();
}
public int Random()
{
Random r=new Random();
int n=Math.abs(r.nextInt()%7+1);
return n;
}
public void lineDown()
{
ny=ny+10;
repaint();
}
public void actionPerformed(ActionEvent e)
{
if(value!=250&&!EndofLine)
{
value=value+5;
if(p==0)
{
p=Random();
}
getShape(p);
lineDown();
}
else
{
p=Random();
ny=0;
EndofLine=false;
value=0;
}
}
}
The shape is a 4 dimensional array from which the width and height of particular rectangle is retrieved which collectively form a desired shape.Through random function we choose the particular shape with getShape() method and using drawRect function we draw the Rectangles.
Now the lineDown function move down the particular shape with increment of 10,and after reaching at the last line the repaint() method is called and new Random shape is falling down from top,The Problem is now how to retain the particular shape at bottom so that next operations can be carried out.
I would create a List of "shapes" that have already fallen down to the bottom of the Tetris board. This List would be held within your Tetris class and when the current falling item hits the bottom of the board or one of the already falled shapes then it should be stopped and added to the fallen list.
Other general tips:
From personal experience, try to stay away from arrays of size > 2 unless its necessary; they are bloated, confusing and hard to maintain. In your case there's a perfect interface to use called Shape. Check out this code
// java.awt.geom.Path2D implements java.awt.Shape
java.awt.geom.Path2D path = new Path2D.Double();
path.moveTo(0, 0);
path.lineTo(2, 0);
path.lineTo(2, 2);
path.lineTo(2, 0);
path.closePath();
path.transform(AffineTransform.getScaleInstance(20, 20));
This creates a Shape that is your basic square! You then have access to great features that you wont have to implement yourself.
PS: As Andrew suggests in the comments, "Also look at Shape based collision detection. It uses Java 2D Area objects to test for intersection."
I was asked by uni to create a 2d racing game in java.
we were told to use one jcomponent in a jframe.
we told to update the game by the swing timer and call repaint() somewhere appropriate in their.
I have now finished but all the way through my use of Graphics g was annoying me. for example below is my gameobject class that players and stuff derive from.
import java.awt.Component;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
/*
* Provides The basic functionality of Displaying a game object on the screen
* and methods able to change the image
*/
public class GameObject {
public Vector position = new Vector();
//image set up variables
protected BufferedImage[] buffImage;
protected ImageIcon icon = new ImageIcon();
protected int numberOfImages;
protected String filePrefix;
protected String fileExt;
//////////////interactive variables
//image
protected int imageNumber = 0;
public GameObject(int numOfImages, String filePre, String fileE)
{
//if this gives grief about constructors implement a custom initObject() method that can be overridden with super.
this.numberOfImages = numOfImages;
buffImage = new BufferedImage[numOfImages];
filePrefix = filePre;
fileExt = fileE;
}
//Adds images to array
protected void initImageArray()
{
for(int i = 0; i <numberOfImages; i++)
{
try{
buffImage[i] = (BufferedImage) ImageIO.read(new File(filePrefix + "/" + Integer.toString(i) + fileExt));
}
catch(Exception e)
{
System.out.println(e);
}
}
}
//Draws object to screen
public void draw(Graphics g, Component c){
icon.setImage(getNextImage());
icon.paintIcon(c, g, position.x, position.y);
}
//returns current image
protected BufferedImage getNextImage(){
return buffImage[imageNumber];
}
//
protected void increaseImageNumber(){
if(imageNumber < numberOfImages-1){
imageNumber++;
}
else{
imageNumber = 0;
}
}
protected void decreaseimageNumber(){
if(imageNumber > 0){
imageNumber--;
}else{
imageNumber = numberOfImages - 1;
}
}
}
The bit specifically i don't think im doing right is passing the same "Graphics g" parameter to every objects draw method. it works but when i tried to place 15 stars in the back ground and change their imageIcon image from one buffered image array to the next everything became very jarred. I put this down to sharing this one graphic class. It could also just be that we were told not to use a threaded solution but i think any new comp should be able to handle 17 images updating and changing. the update timer is at every 33 milliseconds.
Thank you to anyone who can help explain to me the best way to achieve what i was after or the proper use/sharing of the graphics object.