I am developing game using canvas. I have drawn grid of circles using loop. I want to get x,y coordinates of circles. For that I have to make those circles clickable so that whenever player click on a circle it should return its coordinates. I will pass those coordinates to lineDraw() method for drawing line between those circles.
This loop is defining grid of circles:
for (int y=0;y<rows;y++)
{
for (int x=0;x<cols;x++)
{
canvas.drawCircle((x + 1) * dw, (y + 1) *(3* dh), 20, pDot);
}
}
Here dw is (displayWidth) and dh is (displayHeight). Please suggest how I should make these circles clickable?
I had played with this project a little after your previous questions. I'm sure this isn't the most optimized way to do this, but without knowing how you plan to implement the game logic, I think this is flexible enough to adapt. The following is your custom View class, which I've renamed Board, in keeping with Java naming conventions.
public class Board extends View
{
Paint pBack = new Paint();
Paint pDot = new Paint();
Paint pLine = new Paint();
int cols = 5;
int rows = 6;
// Default initialization = false
boolean[][] dots = new boolean[cols][rows];
int canWidth = 0;
int canHeight = 0;
float xStep = 0;
float yStep = 0;
float[] xCoords = new float[cols];
float[] yCoords = new float[rows];
public Board(Context context)
{
super(context);
pBack.setARGB(255, 255, 102, 0);
pDot.setARGB(255, 255, 255, 255);
pLine.setStrokeWidth(5);
pLine.setARGB(255, 90, 10, 0);
}
public void setDots(boolean[][] dotSelected)
{
this.dots = dotSelected;
}
public boolean[][] getDots()
{
return dots;
}
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
canWidth = w;
canHeight = h;
xStep = canWidth / (cols + 1);
yStep = canHeight / (rows + 1);
for (int y = 0; y < rows; y++)
{
yCoords[y] = (y + 1) * yStep;
}
for (int x = 0; x < cols; x++)
{
xCoords[x] = (x + 1) * xStep;
}
}
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
canvas.drawPaint(pBack);
// Grid, lines and box markings
for (int y = 0; y < rows; y++)
{
canvas.drawLine(xStep, yCoords[y], cols * xStep, yCoords[y], pDot);
for (int x = 0; x < cols; x++)
{
if (y == 0)
{
canvas.drawLine(xCoords[x], yStep, xCoords[x], rows * yStep, pDot);
}
if (dots[x][y])
{
boolean left = x > 0 && dots[x - 1][y];
boolean up = y > 0 && dots[x][y - 1];
if (left)
{
canvas.drawLine(xCoords[x], yCoords[y], xCoords[x - 1], yCoords[y], pLine);
}
if (up)
{
canvas.drawLine(xCoords[x], yCoords[y], xCoords[x], yCoords[y - 1], pLine);
}
if (left && up && dots[x - 1][y - 1])
{
canvas.drawCircle(xCoords[x] - xStep / 2, yCoords[y] - yStep / 2, 10, pLine);
}
}
}
}
// Dots
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < cols; x++)
{
canvas.drawCircle(xCoords[x], yCoords[y], 20, pDot);
if (dots[x][y])
{
canvas.drawCircle(xCoords[x], yCoords[y], 15, pBack);
}
}
}
}
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);
if (event.getAction() != MotionEvent.ACTION_DOWN)
return true;
int xNear = 0;
int yNear = 0;
float xMin = canWidth;
float yMin = canHeight;
for (int x = 0; x < cols; x++)
{
if (Math.abs(xCoords[x] - event.getX()) < xMin)
{
xMin = Math.abs(xCoords[x] - event.getX());
xNear = x;
}
}
for (int y = 0; y < rows; y++)
{
if (Math.abs(yCoords[y] - event.getY()) < yMin)
{
yMin = Math.abs(yCoords[y] - event.getY());
yNear = y;
}
}
dots[xNear][yNear] = !dots[xNear][yNear];
invalidate();
return true;
}
}
Store the data of your circles (for instance the position and the radius) in a list and check each of them for mouse collision(register a mouseeventlistener).
public class Circle
{
private int radius;
private int positionX;
private int positionY;
public Circle(int positionX, int positionY, int radius)
{
this.radius = radius;
this.positionX = positionX;
this.positionY = positionY;
}
public int getPositionX()
{
return this.positionX;
}
public int getPositionY()
{
return this.positionY;
}
public boolean contains(int posX, int posY)
{
int distanceX = this.positionX - posX;
int distanceY = this.positionY - posY;
return Math.sqrt((distanceX * distanceX) + (distanceY * distanceY)) <= this.radius;
}
Related
I am currently just messing around with some code and I keep running into an issue. I want to create ten circles and simply have them bounce around the window. I've had a couple of problems (like when I want the circles to bounce off the wall, for some reason the 400,400 window isn't actually that size. I have the circles collide on the right by checking if x + width >= 400, but it bounces outside the screen unless I change the 400 to 380?), but my main issue is that when I create the circles, I want them to be in different locations (so they aren't colliding before they can even move). I am trying to get it so that if a circle is going to be 'inside' another circle then instead create random x and y coordinates again until it isn't inside another circle. But for some reason, if I put r.nextInt() inside the while loop it keeps giving me the same values. Can anyone help?
p.s. I wouldn't mind advice on any other mistakes I have made.
package practicedots;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PracticeDots extends JPanel {
float dots[][] = new float[10][7];
Random r = new Random();
boolean first = true;
float x = 0;
float y = 0;
float xAccel = 0;
float yAccel = 0;
int wall = 380;
int width = 50;
float radius = 0;
float centreX = 0;
float centreY = 0;
boolean collision;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new PracticeDots());
f.setPreferredSize(new Dimension(400, 400));
f.setResizable(true);
f.pack();
f.setVisible(true);
}
/**
*
* #return
*/
public float[][] CreateDots() {
if (first == true) {
for (int i = 0; i < 10; i++) {
while(collision == true){
x = r.nextInt(300);
y = r.nextInt(300);
xAccel = r.nextFloat() / 2;
yAccel = r.nextFloat() / 2;
radius = width/2;
centreX = x + radius;
centreY = y + radius;
dots[i][0] = x;
dots[i][1] = y;
dots[i][2] = xAccel;
dots[i][3] = yAccel;
dots[i][4] = radius;
dots[i][5] = centreX;
dots[i][6] = centreY;
bounce();
}
}
first = false;
} else if (first == false) {
for (int i = 0; i < 10; i++) {
dots[i][0] = dots[i][0] + dots[i][2];
dots[i][1] = dots[i][1] + dots[i][3];
if (dots[i][0] >= wall - width) {
dots[i][2] = -dots[i][2];
}
if (dots[i][1] >= wall - 20 - width) {
dots[i][3] = -dots[i][3];
}
if (dots[i][0] < 0) {
dots[i][2] = -dots[i][2];
}
if (dots[i][1] < 0) {
dots[i][3] = -dots[i][3];
}
bounce();
}
}
repaint();
return dots;
}
//(x2-x1)^2 + (y1-y2)^2 <= (r1+r2)^2
public void bounce() {
for (int i = 0; i < 10; i++) {
for (int a = 0; a < 10; a++) {
if (a != i) {
System.out.println((dots[i][0] - dots[a][0])*(dots[i][0] - dots[a][0]) + (dots[i][1] - dots[a][1])*(dots[i][1] - dots[a][1]) <= (dots[i][4] + dots[a][4]) * (dots[i][4] + dots[a][4]));
collision = (dots[i][0] - dots[a][0])*(dots[i][0] - dots[a][0]) + (dots[i][1] - dots[a][1])*(dots[i][1] - dots[a][1]) <= (dots[i][4] + dots[a][4]) * (dots[i][4] + dots[a][4]);
}
}
}
}
/**
*
* #param g
*/
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < 10; i++) {
CreateDots();
g.drawOval((int) dots[i][0], (int) dots[i][1], width, width);
g.fillOval((int) dots[i][0], (int) dots[i][1], width, width);
}
}
}
<!-- end snippet -->
There were a couple of problems:
During bounce you should return the first time you find a collision, otherwise the collision will be set to true, but then could be set back to false on the next iteration in the for-loop.
In the first == true condition, you should initialize collision to true or it will never do the while loop at all. Either that or change it to a do-while.
During paintComponent you should not call CreateDots within the for-loop since it loops over all dots itself. Just call it before.
The code seems to work with these changes (including width of 400 not 380):
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PracticeDots extends JPanel {
float dots[][] = new float[10][7];
Random r = new Random();
boolean first = true;
float x = 0;
float y = 0;
float xAccel = 0;
float yAccel = 0;
int wall = 400;
int width = 50;
float radius = 0;
float centreX = 0;
float centreY = 0;
boolean collision;
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new PracticeDots());
f.setPreferredSize(new Dimension(400, 400));
f.setResizable(true);
f.pack();
f.setVisible(true);
}
public float[][] CreateDots() {
if (first == true) {
for (int i = 0; i < 10; i++) {
do {
x = r.nextInt(300);
y = r.nextInt(300);
xAccel = r.nextFloat() / 2;
yAccel = r.nextFloat() / 2;
radius = width / 2;
centreX = x + radius;
centreY = y + radius;
dots[i][0] = x;
dots[i][1] = y;
dots[i][2] = xAccel;
dots[i][3] = yAccel;
dots[i][4] = radius;
dots[i][5] = centreX;
dots[i][6] = centreY;
bounce();
} while (collision == true);
}
first = false;
} else {
for (int i = 0; i < 10; i++) {
dots[i][0] = dots[i][0] + dots[i][2];
dots[i][1] = dots[i][1] + dots[i][3];
if (dots[i][0] >= wall - width) {
dots[i][2] = -dots[i][2];
}
if (dots[i][1] >= wall - 20 - width) {
dots[i][3] = -dots[i][3];
}
if (dots[i][0] < 0) {
dots[i][2] = -dots[i][2];
}
if (dots[i][1] < 0) {
dots[i][3] = -dots[i][3];
}
bounce();
}
}
repaint();
return dots;
}
public void bounce() {
collision = false;
for (int i = 0; i < 10; i++) {
for (int a = 0; a < 10; a++) {
if (a != i && !(dots[a][0] == 0 && dots[a][1] == 0)) {
boolean thisCollision = (dots[i][0] - dots[a][0]) * (dots[i][0] - dots[a][0]) + (dots[i][1] - dots[a][1]) * (dots[i][1] - dots[a][1]) <= (dots[i][4] + dots[a][4]) * (dots[i][4] + dots[a][4]);
// System.out.println("collision: "+collision+" i="+i+" a="+a);
if (thisCollision) {
collision = true;
return;
}
}
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
CreateDots();
for (int i = 0; i < 10; i++) {
g.drawOval((int) dots[i][0], (int) dots[i][1], width, width);
g.fillOval((int) dots[i][0], (int) dots[i][1], width, width);
}
}
}
I am basically making a battleship guessing game where you have to the position of a ship by the click of your mouse. When a position of the ship is guessed correctly it deletes that ship cell from the array and when every cell is guessed correctly, the game is over.
What I am now struggling on is to
keep the ship cells within the canvas
convert the mouse position in pixels into the row and column on the grid
if the guess is correct, add the guess to the hit array and if missed adding it to the miss array.
when a guess is made, in addition to colouring the cell, print either “Hit!” or “Miss!” on the cell
sinking the ship when all cells have been hit
In your code you've mixed rows and columns. The x coordinate goes from the left to the right, this are the columns. The y axis goes from the top to the bottom and corresponds to the rows.
Don't store column, row, hit and miss in arrays. But use 2-dimensional arrays to store the position of the ship and the positions of mouse clicks:
boolean [][] ship;
boolean [][] click;
keep the ship cells within the canvas
If the direction is horizontal, then the x start position of the ship has to be less than NUM_COLS - shipLength:
randomX = (int)random(NUM_COLS - shipLength);
randomY = (int)random(NUM_ROWS);
If the direction is horizontal, then the y start position of the ship has to be less than NUM_ROWS - shipLength:
randomX = (int)random(NUM_COLS);
randomY = (int)random(NUM_ROWS - shipLength);
Call randomShip in setup rather than draw:
void setup() {
size(600, 500);
randomShip();
println(store);
}
void draw() {
// randomShip(); <---- delete
drawCells (row, column, shipLength, (255) );
}
Generate the random position and size of the ship in randomShip;
void randomShip () {
ship = new boolean[NUM_COLS][NUM_ROWS];
click = new boolean[NUM_COLS][NUM_ROWS];
shipLength = (int)random (3, 8);
int store = (int)random(vert, horz);
if (store >= 0) {
int randomX = (int)random(NUM_COLS - shipLength);
int randomY = (int)random(NUM_ROWS);
for (int i = 0; i < shipLength; i++ ) {
ship[randomX + i][randomY] = true;
}
} else {
int randomX = (int)random(NUM_COLS);
int randomY = (int)random(NUM_ROWS - shipLength);
for (int i = 0; i < shipLength; i++ ) {
ship[randomX][randomY+1] = true;
}
}
println(shipLength);
}
convert the mouse position in pixels into the row and column on the grid
if the guess is correct, add the guess to the hit array and if missed adding it to the miss array.
The cell which was clicked can be get by the dividing the mouse coordinates mouseX and mouseY by CELLSIZE
int cell_x = mouseX / CELLSIZE;
int cell_y = mouseY / CELLSIZE;
Store mark the clicked cells and count the hits and miss in mouseClicked:
void mouseClicked () {
int cell_x = mouseX / CELLSIZE;
int cell_y = mouseY / CELLSIZE;
if (!click[cell_x][cell_y]) {
click[cell_x][cell_y] = true;
if ( ship[cell_x][cell_y] ) {
hitCount ++;
} else {
missCount ++;
}
}
}
when a guess is made, in addition to colouring the cell, print either “Hit!” or “Miss!” on the cell
Evaluate the ship position (ship[][]) and clicked positions (click[][]) in drawCells. Draw the cells and the text dependent on the states in 2 nested loops:
void drawCells(int colour) {
for (int i = 0; i < NUM_COLS; i++) {
for (int j = 0; j < NUM_ROWS; j++) {
float x = i * CELLSIZE;
float y = j * CELLSIZE;
if (ship[i][j]) {
fill (colour);
rect(x, y, CELLSIZE, CELLSIZE);
}
if (click[i][j]) {
fill(255, 0, 0);
textSize(15);
text(ship[i][j] ? "hit" : "miss", x+10, y+30);
}
}
}
}
sinking the ship when all cells have been hit
Handle the end of the game in draw:
e.g.
void draw() {
drawCells(255);
if (hitCount == shipLength ) {
// [...]
}
}
Full code listing:
final int CELLSIZE = 50;
final int NUM_ROWS = 10;
final int NUM_COLS = 12;
int horz = (int)random(50);
int vert = (int)random(-50);
int store;
int shipLength;
boolean [][] ship;
boolean [][] click;
int hitCount = 0;
int missCount = 0;
void setup() {
size(600, 500);
randomShip();
println(store);
}
void draw() {
drawCells(255);
if (hitCount == shipLength ) {
// [...]
}
}
void drawCells(int colour) {
for (int i = 0; i < NUM_COLS; i++) {
for (int j = 0; j < NUM_ROWS; j++) {
float x = i * CELLSIZE;
float y = j * CELLSIZE;
if (ship[i][j]) {
fill (colour);
rect(x, y, CELLSIZE, CELLSIZE);
}
if (click[i][j]) {
fill(255, 0, 0);
textSize(15);
text(ship[i][j] ? "hit" : "miss", x+10, y+30);
}
}
}
}
void randomShip () {
ship = new boolean[NUM_COLS][NUM_ROWS];
click = new boolean[NUM_COLS][NUM_ROWS];
hitCount = 0;
missCount = 0;
shipLength = (int)random (3, 8);
int store = (int)random(vert, horz);
if (store >= 0) {
int randomX = (int)random(NUM_COLS - shipLength);
int randomY = (int)random(NUM_ROWS);
for (int i = 0; i < shipLength; i++ ) {
ship[randomX + i][randomY] = true;
}
} else {
int randomX = (int)random(NUM_COLS);
int randomY = (int)random(NUM_ROWS - shipLength);
for (int i = 0; i < shipLength; i++ ) {
ship[randomX][randomY+1] = true;
}
}
println(shipLength);
}
void mouseClicked () {
int cell_x = mouseX / CELLSIZE;
int cell_y = mouseY / CELLSIZE;
if (!click[cell_x][cell_y]) {
click[cell_x][cell_y] = true;
if ( ship[cell_x][cell_y] ) {
hitCount ++;
} else {
missCount ++;
}
}
}
I am getting strange rings of black on my spheres when I render with lighting. I just added lighting and I cannot figure out why the black rings are being created.
Here is my code for my tracer.
public class Tracer {
public Camera Cam;
public int Width, Height;
public BufferedImage Image;
public Color BackGroundColor;
public int StartX, StartY, EndX, EndY,RowCount,ColCount;
public ArrayList<GeometricObject> GeoObjects;
public ArrayList<LightObject> LightObjects;
public boolean Tracing;
public double AmbientLight;
public Tracer(Camera cam, int width, int height, BufferedImage image, Color backGroundColor, int startX, int startY, int endX, int endY, int rowCount, int colCount, ArrayList<GeometricObject> Geoobjects,ArrayList<LightObject> Lightobjects,double ambientLight) {
super();
Cam = cam;
Width = width;
Height = height;
Image = image;
BackGroundColor = backGroundColor;
StartX = startX;
StartY = startY;
EndX = endX;
EndY = endY;
RowCount = rowCount;
ColCount = colCount;
GeoObjects = Geoobjects;
LightObjects = Lightobjects;
if(ambientLight > 1){
AmbientLight = 1;
}else if(ambientLight < 0){
AmbientLight = 0;
}else{
AmbientLight = ambientLight;
}
}
public void TracePixelFast(int x, int y) {
Color color = new Color(BackGroundColor.r,BackGroundColor.g,BackGroundColor.b);
for(int o = 0;o < GeoObjects.size();o++){
GeometricObject GO = GeoObjects.get(o);
Ray r = new Ray(Cam.GetRayPos(Width, Height, x, y, 1, 1, RowCount, ColCount), Cam.GetRayDir(Width, Height, x, y, 1,1, RowCount, ColCount));
double hit = GO.hit(r);
if (hit != 0.0) {
color = Cal_Pixel(x,y);
Image.setRGB(x, y, color.toInt());
break;
}
}
}
public void TracePixelSmooth(int x, int y) {
Image.setRGB(x, y,Cal_Pixel(x,y).toInt());
}
public Color Cal_Pixel(int x,int y){
Color color = new Color(BackGroundColor);
Color colorh = new Color(BackGroundColor);
Color bgc = new Color(BackGroundColor);
int HIT = 0;
int MISS = 0;
for (int row = 0; row < RowCount; row++) {
for (int col = 0; col < ColCount; col++) {
double min = Double.MAX_VALUE;
for (int o = 0; o < GeoObjects.size(); o++) {
GeometricObject GO = GeoObjects.get(o);
Ray r = new Ray(Cam.GetRayPos(Width, Height, x, y, row, col, RowCount, ColCount),Cam.GetRayDir(Width, Height, x, y, row, col, RowCount, ColCount));
double hit = GO.hit(r);
if (hit != 0.0 && hit < min) {
min = hit;
colorh = ShadePixel(GO, r, hit);
HIT++;
} else {
double min2 = Double.MAX_VALUE;
for (int o2 = 0; o2 < GeoObjects.size(); o2++) {
if(o!=o2){
GeometricObject GO2 = GeoObjects.get(o2);
double hit2 = GO2.hit(r);
if (hit2 != 0.0 && hit2 < min2) {
min2 = hit2;
bgc = ShadePixel(GO2, r, hit2);
}
}
}
MISS++;
}
}
}
}
for(int h = 0;h < HIT;h++){
color.Add(colorh);
}
for(int m = 0;m < MISS;m++){
color.Add(bgc);
}
color.Divide(RowCount * ColCount);
return color;
}
public Color ShadePixel(GeometricObject GO,Ray ray,double t){
ArrayList<Color> PixelShade = new ArrayList<Color>();
Normal normal = GO.Cal_Normal(ray, t);
for(int l = 0;l < LightObjects.size();l++){
LightObject light = LightObjects.get(l);
Vector3D r_Dir = light.Pos.Sub(normal.Origin);
r_Dir.normalize();
Ray raytolight = new Ray(normal.Origin,r_Dir);
int WAS_HIT = 0;
for(int o = 0;o < GeoObjects.size();o++){
GeometricObject NGO = GeoObjects.get(o);
double hit = NGO.hit(raytolight);
if (hit != 0.0) {
WAS_HIT = 1;
}
}
if(WAS_HIT == 0){
double Dot = normal.Direction.Dot(r_Dir);
if(Dot < 0){
Dot = 0;
}
double Diffuse = 1 - AmbientLight;
Color color = new Color(GO.Color);
double Shade = AmbientLight + Diffuse*Dot;
color.Mul(Shade);
PixelShade.add(color);
}else{
Color color = new Color(GO.Color);
double Shade = AmbientLight;
color.Mul(Shade);
PixelShade.add(color);
}
}
Color Final = new Color();
for(int s = 0;s < PixelShade.size();s++){
Final.Add(PixelShade.get(s));
}
Final.Divide(PixelShade.size());
return Final;
}
public void TraceArea(boolean SmoothTracing) {
Tracing = true;
if(SmoothTracing){
for (int x = StartX; x < EndX; x++) {
for (int y = StartY; y < EndY; y++) {
TracePixelSmooth(x,y);
}
}
}else{
for (int x = StartX; x < EndX; x++) {
for (int y = StartY; y < EndY; y++) {
TracePixelFast(x,y);
}
}
}
}
}
And here is the code for the sphere.
public class Sphere extends GeometricObject{
public Vector3D Center;
public double Radius;
public Sphere(Vector3D Center,double Radius,Color Color){
this.Center = Center;
this.Radius = Radius;
this.Color = Color;
}
public double hit(Ray ray) {
double a = ray.Direction.Dot(ray.Direction);
double b = 2 * ray.Origin.Sub(Center).Dot(ray.Direction);
double c = ray.Origin.Sub(Center).Dot(ray.Origin.Sub(Center))-Radius*Radius;
double discreminant = b*b-4*a*c;
if(discreminant < 0.0f){
return 0.0;
}else{
double t = (-b - Math.sqrt(discreminant))/(2*a);
if(t > 10E-9){
return t;
}else{
return 0.0;
}
}
}
public Normal Cal_Normal(Ray ray,double t) {
Vector3D NPos = new Vector3D(ray.Origin.x + ray.Direction.x*t,ray.Origin.y + ray.Direction.y*t,ray.Origin.z + ray.Direction.z*t);
Vector3D NDir = NPos.Sub(Center).Div(Radius);
return new Normal(NPos,NDir);
}
}
I am sure the problem is in shadepixel() but I could be wrong.
I just found out that the more objects that I add the more rings there are:
1 object no rings.
2 objects 1 ring.
3 objects 2 rings.
If you need me to post more of my code.Just ask and I will.
When I get back from school I will post my color class and fix the color problem. I still do not understand why the more objects (spheres) I add, the more rings there are. Can anyone explain to me why this is happening?
Here is my Color code.
public class Color {
public float r,g,b;
public Color(){
r = 0.0f;
g = 0.0f;
b = 0.0f;
}
public Color(float fr,float fg,float fb){
r = fr;
g = fg;
b = fb;
}
public Color(Color color){
r = color.r;
g = color.g;
b = color.b;
}
public void Add(Color color){
r += color.r;
g += color.g;
b += color.b;
}
public void Divide(int scalar){
r /= scalar;
g /= scalar;
b /= scalar;
}
public void Mul(double mul){
r *= mul;
g *= mul;
b *= mul;
}
public int toInt(){
return (int) (r*255)<<16 | (int) (g*255)<<8 | (int) (b*255);
}
There are multiple issues with this code, but the direct reason for the rings is that color component values are overflowing 0-255 range. This in turn is caused by incorrect calculations in what I take to be an attempt at antialiasing in Cal_Pixel(), as well as by no control whatsoever of numeric range in ShadePixel().
Think about how you can visually debug this scene.
First are the normals correct? Display them as the colour to see.
Taking the range for each component [-1..1] to the range [0..255]:
r = 255*(n.x + 1)/2;
g = 255*(n.y + 1)/2;
b = 255*(n.z + 1)/2;
Once you think they look correct move on to the next stage and build it up stage by stage.
e.g. you might look at if your dot product is as expected (again [-1..1] because the vectors are supposedly normalised):
r = 255*(dot + 1)/2;
g = 255*(dot + 1)/2;
b = 255*(dot + 1)/2;
I have trouble with performance when I am rotating every image, when drawing it FPS has dropped from 1400 to 6. Can I rotate BufferedImage object just after creating it, so the calculation happens only once?
There is my Grid Control class: (Drawing class, problem method is drawRotated())
package cs.meowxiik.universes.graphics;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.util.Observer;
import cs.meowxiik.universes.map.Map;
import cs.meowxiik.universes.map.Tile;
public class GridControl {
int width;
int height;
int xcells;
int ycells;
int cellWidth;
int cellHeight;
int maxZoom = 80;
int minZoom = 30;
private Map activeMap;
public GridControl(int width, int height, int xcells, int ycells) {
this.width = width;
this.height = height;
this.xcells = xcells;
this.ycells = ycells;
cellWidth = width / xcells;
cellHeight= height/ ycells;
}
public GridControl(int width, int height, int cellWidth, int cellHeight, int thisDoesntMatterJustForOverloading) {
this.width = width;
this.height = height;
this.cellWidth = cellWidth;
this.cellHeight = cellHeight;
xcells = width / cellWidth;
ycells = height / cellHeight;
}
public void drawGrid(Graphics g){
for(int i = 0; i < xcells; i++){
for(int ii = 0; ii <ycells; ii++){
g.drawRect(i * cellWidth, ii * cellHeight, cellWidth, cellHeight);
}
}
}
public int getCellSize() {
return cellWidth;
}
public void editCellSize(int i) {
if(i == 0)return;
System.out.println("Resizing: " + i);
//Pokud je i menší jak 0 -> člověk se pokouší přibližovat
if(i < 0 && xcells > maxZoom)return;
if(i > 0 && xcells < minZoom)return;
this.cellWidth += i;
this.cellHeight += i;
xcells = width / cellWidth;
ycells = height / cellHeight;
}
public void setActiveMap(Map map){
this.activeMap = map;
}
public void drawMap(Graphics g, Canvas canvas){
if(activeMap != null){
for(int i = 0; i < xcells; i++){
for(int ii = 0; ii <ycells; ii++){
drawRotated(activeMap.getTiles()[i][ii].getTexture(),activeMap.getTiles()[i][ii].getDegrees(), i*cellWidth, ii*cellWidth,canvas, g, null);
//ImageObserver observer = null;
//g.drawImage(activeMap.getTiles()[i][ii].getTexture(), i*cellWidth, ii*cellWidth, observer);
}
}
}
}
public Tile getTileByCoordinate(int x, int y){
int cellx = x / this.cellWidth;
int celly = y / this.cellHeight;
return activeMap.getTiles()[cellx][celly];
}
public boolean isWalkable(int x, int y){
return getTileByCoordinate(x,y).getWalkable();
}
public void drawRotated(BufferedImage img,double rotationRequired,int x,int y,Canvas canvas, Graphics g, Observer observer){
//double rotationRequired = Math.toRadians(degrees);
double locationX = img.getWidth() / 2;
double locationY = img.getHeight() / 2;
AffineTransform tx = AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
// Drawing the rotated image at the required drawing locations
g.drawImage(op.filter(img, null), x, y, null);
}}
My Tile method:
public class Tile {
boolean walkable;
BufferedImage image;
double radians;
int ID; //0 - floor, 1 - wall
public Tile(boolean walkable, BufferedImage image, int ID) {
this.walkable = walkable;
this.image = image;
this.ID = ID;
}
public BufferedImage getTexture() {
return image;
}
public boolean getWalkable() {
return walkable;
}
public int getDegrees() {
return (int) Math.toDegrees(radians);
}
public int getID() {
return ID;
}
public void setTexture(BufferedImage image, int degrees) {
this.image = image;
this.radians = Math.toRadians(degrees);
}
}
And my Map creator: (the rotating part is broken, I'll fix that later, now I need to solve my 6-FPS problem)
package cs.meowxiik.universes.map;
import cs.meowxiik.universes.graphics.GraphicsManager;
public class MapCreator {
GraphicsManager graphics;
public MapCreator(GraphicsManager graphics) {
this.graphics = graphics;
}
public Map getSpaceStationMap(){
Map map;
int x = 32;
int y = 18;
Tile[][] tiles = new Tile[x][y];
for(int i = 0; i < x; i++){
for(int ii = 0; ii < y; ii++){
tiles[i][ii] = new Tile(true, graphics.floor, 0);
}
}
for(int i = 0; i < x; i++){
for(int ii = 0; ii < y; ii++){
if(i == 0 || ii == 0 || i == x-1 || ii == y-1)tiles[i][ii] = new Tile(false,graphics.stWallZero, 1); //tiles.get(i).set(ii, new Tile(false,graphics.wall));
}
}
for(int i = 0; i < x; i++){
for(int ii = 0; ii < y; ii++){
if(tiles[i][ii].getID() == 0)break;
boolean connectedUp = false;
boolean connectedLeft = false;
boolean connectedRight = false;
boolean connectedBottom = false;
if(i + 1 < tiles.length)
if(tiles[i + 1][ii + 0].getID() == 1)
connectedRight = true;
if(i != 0)
if(tiles[i - 1][ii + 0].getID() == 1)
connectedLeft = true;
if(ii + 1 < tiles[i].length)
if(tiles[i + 0][ii + 1].getID() == 1)
connectedBottom = true;
if(ii != 0)
if(tiles[i + 0][ii - 1].getID() == 1)
connectedUp = true;
if(connectedUp && !(connectedLeft || connectedRight || connectedBottom))tiles[i][ii].setTexture(graphics.stWallOne, 0);
if(connectedLeft && !(connectedUp || connectedRight || connectedBottom))tiles[i][ii].setTexture(graphics.stWallOne, 90);
if(connectedRight && !(connectedUp || connectedLeft || connectedBottom))tiles[i][ii].setTexture(graphics.stWallOne, 180);
if(connectedBottom && !(connectedUp || connectedRight || connectedLeft))tiles[i][ii].setTexture(graphics.stWallOne, 270);
if((connectedUp && connectedBottom) && !(connectedLeft || connectedRight))tiles[i][ii].setTexture(graphics.stWallTwo, 90);
if(!(connectedUp && connectedBottom) && !(connectedLeft || connectedRight))tiles[i][ii].setTexture(graphics.stWallTwo, 0);
}
}
map = new Map(x,y,tiles);
return map;
}
}
Given this code
public void drawRotated(BufferedImage img,double rotationRequired,int x,int y,Canvas canvas, Graphics g, Observer observer) {
//double rotationRequired = Math.toRadians(degrees);
double locationX = img.getWidth() / 2;
double locationY = img.getHeight() / 2;
AffineTransform tx = AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
BufferedImage rotatedImage = op.filter(img, null); // my edit here
// Drawing the rotated image at the required drawing locations
g.drawImage(rotatedImage , x, y, null);
}
The rotation of the image to get rotatedImage is only dependant upon it's size (width/height) and the required rotation.
From my reading of your code the required rotation is largely fixed. The rotation is known when the setTexture method of Title is called.
Sine this is the case, rotatedImage can be computed in the setTexture method. Just create a new attribute that stores the computed rotated image. Don't destroy the original.
If setTexture is called as often as drawRotated then this won't deliver the performance increase you desire.
I am currently making a game in Java and I am trying to draw an image on my screen, but nothing show up ( only a black screen but no errors ) :(
Here is the code to import the image:
public static Bitmap loadBitmap(String fileName) {
try {
BufferedImage img = ImageIO.read(Art.class.getResource(fileName));
int w = img.getWidth();
int h = img.getHeight();
Bitmap result = new Bitmap(w, h);
img.getRGB(0, 0, w, h, result.pixels, 0, w);
for (int I = 0; I < result.pixels.length; i++) {
int in = result.pixels[i];
int col = (in & 0xf) >> 2;
if (in == 0xffff00ff) col = -1;
result.pixels[i] = col;
}
return result;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
And the Bitmap class:
public void draw(Bitmap bitmap, int xOffs, int yOffs)
{
for(int y = 0; y < bitmap.height; y++)
{
int yPix = y + yOffs;
if(yPix < 0 || yPix >= height) continue;
for(int x = 0; x < bitmap.width; x++)
{
int xPix = x + xOffs;
if(xPix < 0 || xPix >= width) continue;
int alpha = bitmap.pixels[x + y * bitmap.width];
if(alpha > 0)
pixels[xPix + yPix * width] = bitmap.pixels[x + y * bitmap.width];
}
}
}
And to draw all of this :
public void render(Game game)
{
for(int y = 0; y < height; y++)
{
float yd = ((y + 0.5f) - height / 2.0f) / height;
if(yd < 0) yd *= -1;
float z = 10 / yd;
for(int x = 0; x < width; x++)
{
float xd = (x - width / 2.0f) / height;
xd *= z;
int xx = (int) (xd) & 7;
int yy = (int) (z + game.time * 0.1f) & 7;
pixels[x + y * width] = Art.floors.pixels[xx + yy * 64];
}
}
}
I have no errors! I don't really understand.. is this a bug caused by alpha or something? Ho and my image.png is 64x64 made in paint.net