I am making a game with a shooter such that when use click it should move left or right but it is made on canvas and onclick listeners didn't work on it so someone told me to get coordinates of canvas and use onclick listeners on it but he don't tell me how to do it
My Code
package --------;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
public class Cannon {
float x = -1; // Cannon's center (x,y)
float y = -1;
float stepX = 40;
int lowerX, lowerY, upperX, upperY;
private Paint paint;
private Context mContext;
// Constructor
public Cannon(int color, Context c) {
paint = new Paint();
paint.setColor(color);
mContext = c;
}
public void setBounds(int lx, int ly, int ux, int uy) {
lowerX = lx;
lowerY = ly;
upperX = ux;
upperY = uy;
x = ux/2;
y = uy;
}
public void moveLeft() {
if (x - 30 > 0) {
x -= stepX;
}
}
public void moveRight() {
if (x + 30 < upperX) {
x += stepX;
}
}
public float getPosition() {
return x;
}
public void draw(Canvas canvas) {
canvas.drawLine(x, y -120, x, y, paint);
canvas.drawRect(x - 90, y - 40, x + 90, y, paint);
}
}
how to use onclick listeners for this rectangle by getting its coordinates to do move left function
You already have a method getPosition, but it only returns the x position.. Create one that returns x and one that returns y, for example:
public float getCannonX(){
return x;
}
public float getCannonY(){
return y;
}
Then in your Activity you can set an onClickListener on your cannon object and access the methods above.
Or you can set an onClickListener on your canvas and use the above methods to check if the cannon coordinates was selected.
You should factor in the size of the cannon object as well
Related
I want to make a game wherein when the main character sprite's X coordinate is less than the middle of the screen, he moves to the right and when it's more than the middle of the screen, he moves to the left. The sprite's animation changes when he is moving and when he is still (after reaching its destination). What I want to know is how can I do this when the sprite and its code for animation is in one class and the code for changing its X coordinate is in another class? Is it best to draw the same sprite in every class? How can I change the sprite when it is moving horizontally and when it is still? I plan to separate the code for what the sprite's actions will be in different classes because i want to call them randomly. Here is my code for the sprite's animation and i have no class for changing the x coordinate yet :
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.jpfalmazan.ninjaassault.NinjaAssault;
public class MainScreen implements Screen {
private static final int FRAME_COLS = 3;
private static final int FRAME_ROWS = 2;
Animation walkAnimation;
Texture walkSheet = new Texture ("ninjaWalk.png");
TextureRegion[] walkFrames;
TextureRegion currentFrame;
Texture holdStart;
float stateTime;
public Texture background;
private NinjaAssault game;
private Music BackgroundSFX;
public float screenWidth = Gdx.graphics.getWidth();
public float screenHeight = Gdx.graphics.getHeight();
float x = screenWidth/2;
float y = screenHeight/2;
public float walkSheetWidth = walkSheet.getWidth();
public float walkSheetHeight = walkSheet.getHeight();
public MainScreen (NinjaAssault game){
this.game = game;
}
#Override
public void show(){
background = new Texture("BGBlue.png");
holdStart = new Texture ("HoldStart.png");
BackgroundSFX = Gdx.audio.newMusic(Gdx.files.internal("data/RADWIMPS-iindesuka.mp3"));
TextureRegion[][] tmp = TextureRegion.split(walkSheet, (int )walkSheetWidth/FRAME_COLS, (int) walkSheetHeight/FRAME_ROWS);
walkFrames = new TextureRegion[FRAME_COLS*FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++){
for (int j = 0; j < FRAME_COLS; j++) {
walkFrames[index++] = tmp[i][j];
}
}
walkAnimation = new Animation(0.0887f, walkFrames);
stateTime = 0f;
}
#Override
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stateTime += Gdx.graphics.getDeltaTime();
currentFrame = walkAnimation.getKeyFrame(stateTime, true);
float hsWidth = holdStart.getWidth();
float hsHeight = holdStart.getHeight();
float currentFrameWidth = (float)(screenHeight*0.15);
float currentFrameHeight = (float)(screenHeight*0.15);
float holdStartWidth = (float)(screenWidth * 0.75);
game.batch.begin();
game.batch.draw(background,0,0, screenWidth,screenHeight);
BackgroundSFX.play();
game.batch.draw(currentFrame, x -currentFrameWidth/2, 0,currentFrameWidth,currentFrameHeight);
game.batch.draw(holdStart, (screenWidth / 2 - (holdStartWidth / 2)), (float) (screenHeight * 0.5), holdStartWidth, holdStartWidth * (hsHeight / hsWidth));
game.batch.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
BackgroundSFX.dispose();
background.dispose();
walkSheet.dispose();
holdStart.dispose();
}
}
I tried to research on how to do this but the answers I get wasn't that helpful.
Simplest way is to create a Player class and put all the code for the animation and frames in there. Then give it a way to save its position. Like a vector or just a float for the x coordinate. Or even better, use a Rectangle. A rectangle will make moving and collision detection much easier.
Something like this:
public class Player{
private Animation walkAnimation;
private Texture walkSheet;
private TextureRegion[] walkFrames;
private TextureRegion currentFrame;
private float stateTime;
private Rectangle bound; //used for positioning and collision detection
public Player(float x, float y, float width, float height){
bound = new Rectangle();
bound.x = x;
bound.y = y;
bound.width = width;
bound.height = height;
walkSheet = new Texture ("ninjaWalk.png");
TextureRegion[][] tmp = TextureRegion.split(walkSheet,(int)walkSheetWidth/FRAME_COLS, (int) walkSheetHeight/FRAME_ROWS);
walkFrames = new TextureRegion[FRAME_COLS*FRAME_ROWS];
int index = 0;
for (int i = 0; i < FRAME_ROWS; i++){
for (int j = 0; j < FRAME_COLS; j++) {
walkFrames[index++] = tmp[i][j];
}
}
walkAnimation = new Animation(0.0887f, walkFrames);
stateTime = 0f;
}
public rectangle getBound(){
return bound;
}
public void update(float delta){
statetime += delta;
currentFrame = walkAnimation.getKeyFrame(stateTime, true);
}
public TextureRegion getCurrentFrame(){
return currentFrame;
}
}
This is just a quick untested example.
You say you want to move the player from another class. I don't know how you plan to do that, but all you need to do to move the player is to manipulate the x and y of the bound.
Just some other comments on you code:
#Override
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
player.update(delta); // to update the player
/***
* This does not have to be set every single frame. Move it to show()
*
float hsWidth = holdStart.getWidth();
float hsHeight = holdStart.getHeight();
float currentFrameWidth = (float)(screenHeight*0.15);
float currentFrameHeight = (float)(screenHeight*0.15);
float holdStartWidth = (float)(screenWidth * 0.75);
****************************************************/
BackgroundSFX.play(); // I am sure you don't need to start playing this every single frame? 60 times a second.
game.batch.begin();
game.batch.draw(background,0,0, screenWidth,screenHeight);
game.batch.draw(player.getCurrentFrame(), player.getBound().x, player.getbound().y, player.getBound().width, player.getBound().height)
game.batch.draw(holdStart, (screenWidth / 2 - (holdStartWidth / 2)), (float) (screenHeight * 0.5), holdStartWidth, holdStartWidth * (hsHeight / hsWidth));
game.batch.end();
}
So I am trying to generate random rectangles that the player must avoid. My collision method was working with a single, randomly generated rectangle. I want to draw 10 or so of these and then I will add a finish line and a timer.
Right now, I understand my problem, but I am not sure how to fix it. The ball/player's movement is executed by changing the x or y coordinates by 10 and then repainting the circle. I currently have the rectangles in the same paint method, so each time the player moves the rectangles are regenerated. I would like them to stay in the same place after the initial random generation. I don't really know how to do this though...
Also, if I can get the rectangles to stay in the same place, will my collision method still work with multiple rectangles? or would I need to revise that as well?
I am just going to post the whole program's code because I'm not sure which parts will need to be revised.
import java.awt.*;
import java.awt.Rectangle;
import java.awt.Shape;
import javafx.scene.shape.*;
import java.awt.event.*;
import java.util.Random;
import java.awt.geom.Area;
import javax.swing.JOptionPane;
import java.applet.Applet;
public class Main extends Applet
implements ActionListener{
boolean end = false;
private Rectangle rectangle;
//creates buttons to move player
private Button run = new Button("Run");
private Button jump = new Button("Jump");
private Button fall = new Button("Fall");
//creates player and obstacles
private Circle player = new Circle(110,110,20);
private makeRect block = new makeRect(150, 120, 30, 10);
//initiates the buttons with actionListener
public void init(){
add(run);
add(jump);
add(fall);
run.addActionListener(this);
jump.addActionListener(this);
fall.addActionListener(this);
}
//draws the player and blocks on the screen
public void paint(Graphics g){
for(int numBlocks = 0; numBlocks<11; numBlocks++){
block.draw(g);}
player.draw(g);
}
//if methods to be control movement
public void actionPerformed(ActionEvent e){
if(e.getSource() instanceof Button){
if(e.getSource() == run)
player.horiz(10);
else if (e.getSource()== jump){
player.vert(-10);
}
else if (e.getSource()== fall){
player.down(10);
}
repaint();
collision();
}
}
public void collision(){
if(player.getBounds().intersects(block.getBounds())){
JOptionPane.showMessageDialog(this, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
end = true;
}
}
class Circle{
private final Color theColor = Color.BLUE;
private int radius;
private int x,y;
public Circle(){
x = 110; y = 110;
radius = 20;
}
public Circle(int x0, int y0, int rad){
x = x0; y = y0; radius = rad;
}
public void draw(Graphics g){
g.fillOval(x - radius, y-radius, 2*radius, 2*radius);
g.setColor(theColor);
}
public void horiz(int val){
for(int c = 0; c<val+1; c++){
x++;
repaint();}
}
public void vert(int val){
y += val;
}
public void down(int val){
y += val;
}
public Rectangle getBounds(){
return new Rectangle(x-radius, y-radius, 2*radius, 2*radius);
}
}
class makeRect{
private int Xmax = 250;
private int Xmin = 140;
private int Wmax = 50;
private int Hmax = 25;
private int Wmin = 10;
private int Hmin = 5;
Random rand = new Random();
private int randx;
private int randh;
private int x, y, width, height;
public makeRect(){
x = 150; y = 120;
width = 30; height = 10;
}
public makeRect(int x0, int y0, int w0, int h0){
x = x0; y = y0; width = w0; height = h0;
}
public void draw(Graphics g) {
int randx = rand.nextInt((Xmax-Xmin)+1)+Xmin;
int randh = rand.nextInt((Hmax-Hmin)+1)+Hmin;
int randw = rand.nextInt((Wmax-Wmin)+1)+Wmin;
g.drawRect(randx, 110+randh, randh, randw);
}
public Rectangle getBounds(){
return new Rectangle(randx, 110+randh, 30, 10);
}
}
}
Thanks!
For that you will need to construct 10 rects (consider using array) first upon initialization, with random postition for each. I mean, postition randomization occurs when the rects are constructed, not when it's drawn.
What you have there is a same rectangle drawn 10 times at different places each time the paint() gets called.
On my class I'm implementing ApplicationListener, so on my create method this is what I do:
public void create(){
camera=new Camera();
camera.setToOrtho(false,screenW,screenH);
}
//then on the render method:
public void render(){
camera.update();
}
But then when I use Gdx.input.getY() the result is reversed, when I go up the Y coordinate is less and when I go down the it gets higher.For better understanding:
Have a look at the camera class and the unproject method. That should translate between screen coordinates and world coordinates. (Probably more efficient way to do this, but for illustration):
float x = Gdx.input.getX();
float y = Gdx.input.getY();
float z = 0.0f;
Vector3 screenCoordinates = new Vector3(x, y, z);
Vector3 worldCoordinates = camera.unproject(screenCoordinates);
Then use the worldCoordinates vector for whatever you need it for.
EDIT: Added small working example and screenshot. My screen capture didn't capture the mouse, thus the red "star". But this simple app displays y coordinates in "initial" and "unprojected" coords as you move the mouse around the screen. Try it for yourself. I think this is what you are getting at, no?
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.Vector3;
public class SimpleInputCoords implements ApplicationListener {
private OrthographicCamera camera;
#Override
public void create() {
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
}
#Override
public void render() {
int x = Gdx.input.getX();
int y = Gdx.input.getY();
int z = 0;
System.out.println("UnmodifiedYCoord:"+y);
Vector3 screenCoordinates = new Vector3(x, y, z);
Vector3 worldCoordinates = camera.unproject(screenCoordinates);
System.out.println("UnprojectedYCoord:"+worldCoordinates.y);
}
#Override
public void dispose() {
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
}
In Java coordinates start in the upper left corner (0,0). On a 100 x 100, (100,0) would be upper right, and (0, 100) would be lower left. So the behavior you are seeing is expected.
http://inetjava.sourceforge.net/lectures/part2_applets/InetJava-2.1-2.2-Introduction-to-AWT-and-Applets_files/image001.gif
I am trying to create a background scrolling for an Android game. Lets say it is a set of images moving at a speed.
To test out few basic elements, I have taken a small, rectangular image and moving it linearly from top to bottom. It moves but I see a small trail, like a rocket going in clouds(haha!). I tried various options in Paint() class to rectify this, but I couldn't.
I will first post a screen shot and then add relevant code.
So, here the vertical line is a single png image:
Now all I am doing is moving this bitmap from a certain (x,y) by increasing y by 5 at a time. It moves, but notice the ends of the image while moving. Sort of a trail, but not a permanent one. I have tried but unable to remove this effect. I tried on Samsung Galaxy S5. I didnot test on any other model.
The code:
The moving vertical image is a Sprite object:
package com.src.*.*;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.Log;
public class Sprite {
private Rect sourceRect; // the rectangle to be drawn from the animation bitmap
private int frameNr; // number of frames in animation
private int currentFrame; // the current frame
private long frameTicker; // the time of the last frame update
private int framePeriod; // milliseconds between each frame (1000/fps)
private int spriteWidth; // the width of the sprite to calculate the cut out rectangle
private int spriteHeight; // the height of the sprite
private int x; // the X coordinate of the object (top left of the image)
private int y; // the Y coordinate of the object (top left of the image)
private Bitmap bitmap;
private float degrees;
private boolean rotate=false;
private Matrix matrix;
private Bitmap reversedBitmap;
private Paint paint;
public Sprite(Bitmap bitmap, int x, int y, int fps, int frameCount) {
this.bitmap = bitmap;
this.x = x;
this.y = y;
currentFrame = 0;
frameNr = frameCount;
spriteWidth = bitmap.getWidth() / frameCount;
spriteHeight = bitmap.getHeight();
sourceRect = new Rect(0, 0, spriteWidth, spriteHeight);
framePeriod = 1000 / fps;
frameTicker = 0l;
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG
| Paint.FILTER_BITMAP_FLAG);
paint.setDither(true);
}
public void animate(){
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void setReverse(Bitmap reverse){
this.reversedBitmap = reverse;
}
public void rorateSprite(float degrees){
if(degrees == 0){
rotate = false;
}else{
rotate = true;
}
this.degrees = degrees;
}
public void draw(Canvas canvas) {
// where to draw the sprite
Rect destRect = new Rect(getX(), getY(), getX() + spriteWidth, getY() + spriteHeight);
if(rotate){
canvas.drawBitmap(reversedBitmap, sourceRect, destRect, paint);
}else{
canvas.drawBitmap(bitmap, sourceRect, destRect, paint);
}
}
public void update(long gameTime){
if (gameTime > frameTicker + framePeriod) {
frameTicker = gameTime;
//Log.i("INFO", "In if loop" + currentFrame + " framenr:" + frameNr);
// increment the frame
currentFrame++;
if (currentFrame >= frameNr) {
currentFrame = 0;
}
}else{
//Log.i("INFO", "in else" + currentFrame + "");
}
// define the rectangle to cut out sprite
//Log.i("INFO", "sprite width: " + spriteWidth);
this.sourceRect.left = currentFrame * spriteWidth;
this.sourceRect.right = this.sourceRect.left + spriteWidth;
}
}
The bitmap is setup as follows:
wallAnimation = new Sprite(resizedBitmapWall, 0, 0, 30, 1);
wallAnimation.setX(margin);
The onDraw and Update for the sprite is as follows. It works without any exception or error. The only issue in all of this is the image having the blurry/tail effect at the ends. I dont even know the right word for it.
Code for onDraw and Update:
#Override
protected void onDraw(Canvas canvas) {
// fills the canvas with black
canvas.drawColor(Color.WHITE);
wallAnimation.draw(canvas);
paint.setColor(Color.BLACK);
for (int i = 0; i < 6; i++) {
canvas.drawLine(margin+laneWidth*i, 0, margin+laneWidth*i, laneHeight, paint);
}
canvas.drawText("High Score: "+ highScore, 10, 10, paint);
}
public void Update(long gameTime) {
// TODO Auto-generated method stub
if(wallState < laneHeight+laneHeight/6){
wallAnimation.setY(wallState);
//wallState+=laneHeight/80;
wallState+=20;
}else{
wallState = 0;
}
}
I'm trying to implement a camera for a 2D game that I'm making... The goal will to have the cam keep the player in the center and the sprites relative to the camera.
To get the hang of normalocity's post, I tried starting off simple by making a Camera Test project, where I'd simulate a camera by drawing a sprite to a JPanel, and moving a "camera" object (which is the JPanel) around and setting the sprite's x,y relative to that.
The Camera, as I said, is the JPanel... and I've added a "world", which is a class with an x,y of 0,0, and w=1000, h=1000. I've included the sprite's location relative to the world as well as the camera. When I move the camera up, the sprite moves down and the player stays in the middle as expected..
But if I keep pressing down, the sprite seems to keep drawing over itself.
My questions are:
Am I on the right track in implementing a camera given the code below?
Why does the sprite start to draw over itself there? It should just disappear off the viewPort/JPanel
Thanks!
Now with PaintComponent(g) added, my JPanel bg color of gray now slides off. Is this supposed to happen?
EDIT: SSCCE of my program:
Main Class:
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class MainSSCCE extends JFrame {
static MainSSCCE runMe;
public MainSSCCE() {
JFrame f = new JFrame("Camera Test");
CameraSSCCE cam = new CameraSSCCE(0, 0, 500, 500);
f.add(cam);
f.setSize(cam.getWidth(), cam.getHeight());
f.setVisible(true);
f.setResizable(false);
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
f.setLocation( (screensize.width - f.getWidth())/2,
(screensize.height - f.getHeight())/2-100 );
}
public static void main(String[] args) {
runMe = new MainSSCCE();
}
}
Camera Class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
//Camera is the JPanel that will draw all objects... each object location will be in relation to the World
public class CameraSSCCE extends JPanel implements KeyListener {
//add world to camera...
private static final long serialVersionUID = 1L;
private int camX, camY, camH, camW;
private SpriteSSCCE sprite;
private PlayerSSCCE player;
private WorldSSCCE world;
public CameraSSCCE(int x, int y, int w, int h) {
camX = x;
camY = y;
camW = w;
camH = h;
sprite = new SpriteSSCCE(this, 300, 300, 20, 20);
player = new PlayerSSCCE(this, camW/2, camH/2, 25, 40);
world = new WorldSSCCE(this, 0, 0, 1000, 1000);
addKeyListener(this);
setFocusable(true);
}
public int getWidth() {
return camW;
}
public int getHeight() {
return camH;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//cam is 500 x 500
g.setColor(Color.gray);
g.fillRect(camX, camY, camW, camH);
//draw sprite at JPanel location if in camera sight
if (((sprite.getX()-camX) >= camX) && ((sprite.getX()-camX) <= (camX+camW)) && ((sprite.getY()-camY) >= camY) && ((sprite.getY()-camY) <= (camY+camH))) {
g.setColor(Color.green);
g.fillRect(sprite.getX()-camX, sprite.getY()-camY, 20, 20);
//Cam Sprite Location
g.setColor(Color.white);
g.drawString("Camera Sprite Location: (" + (sprite.getX()-camX) + ", " + (sprite.getY()-camY) + ")", sprite.getX()-camX, sprite.getY()-camY);
}
//Player location (center of Camera... Camera follows player)
g.setColor(Color.cyan);
g.fillRect(player.getX()-player.getWidth(), player.getY()-player.getWidth(), player.getWidth(), player.getHeight());
g.setColor(Color.white);
//World Sprite Location
g.drawString("World Sprite Location: (" + sprite.getX() + ", " + sprite.getY() + ")", sprite.getX(), sprite.getY());
//Cam Player Location
g.drawString("Cam Player Location: (" + (camW/2-player.getWidth()) + ", " + (camH/2-player.getHeight()) + ")", camW/2-player.getWidth(), camH/2-player.getHeight());
}
public void keyPressed(KeyEvent e) {
//move camera right in relation to World
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
camX+=5;
}
//move camera left in relation to World
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
camX-=5;
}
//move camera up in relation to World
if (e.getKeyCode() == KeyEvent.VK_UP) {
camY-=5;
}
//move camera down in relation to World
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
camY+=5;
}
repaint();
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
World Class:
public class WorldSSCCE {
private int x, y, w, h;
private CameraSSCCE camera;
public WorldSSCCE(CameraSSCCE cam, int x, int y, int w, int h) {
camera = cam;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public int getWidth() {
return this.w;
}
public int getHeight() {
return this.h;
}
}
Player Class:
import java.awt.Dimension;
public class PlayerSSCCE {
private int x, y, w, h;
private CameraSSCCE cam;
public PlayerSSCCE(CameraSSCCE cm, int x, int y, int w, int h) {
cam = cm;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public int getWidth() {
return this.w;
}
public int getHeight() {
return this.h;
}
public void setX(int val) {
this.x += val;
}
public void setY(int val) {
this.y += val;
}
}
Sprite Class:
import java.awt.Color;
import java.awt.Graphics;
public class SpriteSSCCE {
private int xLoc, yLoc, width, height;
private CameraSSCCE world;
public SpriteSSCCE(CameraSSCCE wld, int x, int y, int w, int h) {
xLoc = x;
yLoc = y;
width = w;
height = h;
world = wld;
}
public int getX() {
return xLoc;
}
public int getY() {
return yLoc;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public void paintComponent(Graphics g) {
g.setColor(Color.green);
g.fillRect(xLoc, yLoc, width, height);
}
}
1) You have not honored the paint chain by calling super.paintComponent(g) in paintComponent(..):
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//do drawing here
}
As per Java docs:
protected void paintComponent(Graphics g)
Further, if you do not invoker super's implementation you must honor
the opaque property, that is if this component is opaque, you must
completely fill in the background in a non-opaque color. If you do not
honor the opaque property you will likely see visual artifacts.
2) Also notice the #Override annotation I added and the fact that I changed public modifier to protected as thats what the access level is defined as in the implementation class which we should keep unless for a specific reason.
3) Also Swing uses Keybindings have a read on How to Use Key Bindings
4) Also have a read on Concurrency in Swing specifically on The Event Dispatch Thread which dictates all swing components be created on EDT via SwingUtillities.invokeXXX(..) block:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//create and manipulate swing components here
}
});
5) You extend the JFrame class and create an instance, this is not what you want rather remove the extends JFrame from the class declaration:
public class MainSSCCE extends JFrame { //<-- Remove extends JFrame
public MainSSCCE() {
JFrame f = new JFrame("Camera Test");//<-- instance is created here
}
}
Your world is a virtual area larger than the screen (or your jpanel for what matters). All objects' positions are relative to the world. Let's call them absolute coordinates.
Your camera is a small rectangular portion of the world (your panel). By moving it you see different world portions. If you could move the camera like in the post you link to, then at some point you would not be able to see neither the player nor the other sprite.
Since your goal is to keep the player centered on the screen what does this mean for our world? This means that the player and the camera are moving together in relation to the world.
Given the above it does not make sense to draw a camera sprite as in your first screenshot. The camera sprite should be either invisible or it should be drawn in the same position with the player sprite. Nor it makes sense to change the camera's absolute coordinates without changing the player's. Those two are moving together. (take this into account in your keyPressed() methods)
Now when you are drawing, you are drawing from the camera's point of view (or in other words in the camera's coordinate system). From that point of view, the camera always see a rectangle of (0, 0, cameraWidth, cameraHeight). That's what you should use when clearing the area with gray color. This will fix your moving background issue. Since camera and player always have the same absolute coordinates the player will always be in the same place (this is what we want). The rest of the sprites will be seen relative to camera.
For each one of them you translate them in the camera's coordinate system when you do (sprite.x - cam.x) and (sprite.y - cam.y). Since they are translated, you only need to check if they are inside the camera's rectangle (0, 0, cameraWidth, cameraHeight). If they are you go ahead and draw them. If not ignore them.
I hope that helps
Note: cameraWidth, cameraHeight are your jpanel's dimensions