Using WASD and arrow keys simultaneously - java

I am developing a two player game in Processing (running on Java). One user will control his character using the WASD keys and the other will control movement using the arrow keys. The problem I am having is that using keyPressed negates WASD when arrows are pressed and vice versa. I have been messing around with it for a really long time. Does anyone know a work around or notice something that I am doing wrong?
//global variables
int wide = 600; //canvas width
int tall = 600; //canvas height
int s = 50; //player size
float speed = 2.5; //player movement speed
//colors
int redColor = #CB4646; //player 1 color
int blueColor = #4652CB; //player 2 color
int backgroundColor = #DBE3B3; //background color
float player1X = 600/3-s; //HOW COME width/3 DOESN'T WORK??????????
float player2X = 600*2/3;
float playerY = 600/2-(s/2);
//players
Player player1 = new Player(player1X, playerY, s, speed, "wasd", redColor); //player 1
Player player2 = new Player(player2X, playerY, s, speed, "arrows", blueColor); //player 2
//setup
void setup(){
background(backgroundColor);
size(wide, tall);
smooth();
println(player2.controls);
}
//draw
void draw(){
background(backgroundColor);
player1.usePlayer();
player2.usePlayer();
}
class Player{
//class variables
float x; // x position
float y; // y position
int s; //size
float speed; //speed
String controls; //controls
int colors; //player color
char keyControls [] = new char [4];
//construct
Player(float tempX, float tempY, int tempS , float tempSpeed, String tempControls, int tempColors){
x = tempX;
y = tempY;
s = tempS;
speed = tempSpeed;
controls = tempControls;
colors = tempColors;
}
void usePlayer(){
// draw player
fill(colors);
rect(x, y, s, s);
//move player
keyPressed();
//wraparound
boundaries();
}
void keyPressed(){
//sets controls for wasd
if(controls == "wasd"){
if(key == 'w' || key == 'W'){
y -= speed; //move forwards
}
if(key == 's' || key == 'S'){
y += speed; //move backwards
}
if(key == 'd' || key == 'D'){
x += speed; //move right
}
if(key == 'a' || key == 'A'){
x -= speed; //move left
}
}
//sets controls for arrows
if(controls == "arrows"){
if(key == CODED){
if(keyCode == UP){
y -= speed; //move forwards
}
if(keyCode == DOWN){
y += speed; //move backwards
}
if(keyCode == RIGHT){
x += speed; //move right
}
if(keyCode == LEFT){
x -= speed; //move left
}
}
}
}
//pacman style wraparound
void boundaries(){
if(x == width) x = 2;
if(y == height) y = 2;
if(x == 0) x = width-s;
if(y == 0) y = height-s;
}
}

Track your keys independently, don't rely on the event globals.
boolean[] keys = new int[255];
void keyPressed() {
keys[keyCode] = true;
}
void keyReleased() {
keys[keyCode] = false;
}
void draw() {
updatePlayers();
drawStuff();
}
void updatePlayers() {
if(keys[LEFT]) { p1.move(-1,0); }
if(keys[RIGHT]) { p1.move(1,0); }
if(keys[UP]) { p1.move(0,-1); }
if(keys[DOWN]) { p1.move(0,1); }
if(keys['a']) { p2.move(-1,0); }
if(keys['d']) { p2.move(1,0); }
if(keys['w']) { p2.move(0,-1); }
if(keys['s']) { p2.move(0,1); }
}
Note this has to be a series of if statements, because you want to handle all pressed keys. If someone's holding left and right, p1 will move left, and right.
Also note that this example code doesn't filter for the higher-than-255 codes you get for special keys, so you probably want to put an "if(keyCode>255) return" at the start of the event handlers.

Is key a global variable? I don't see it getting passed to the Player. If it's global, then it can only hold one key at a time, which precludes controlling two players at once.

Here is my Arduino/Processing code that I used to handle simultaneous key presses (to move diagonally). It fixes the issue with boolean[] cannot be cast to int[] error as shown by #Brannon and uses keyCodes instead of key.
import processing.serial.*;
​
boolean[] keys = new boolean[255];
Serial port;
​
void setup() {
port = new Serial(this, Serial.list()[1], 9600);
​
}
​
void draw() {
// loop through boolean array and see which ones (index = keyCode)
// are true, then write to them.
for(int i = 0; i < 255; i++) {
if(keys[i]) {
if (i == 87) { port.write('w'); }
if (i == 65) { port.write('a'); }
if (i == 83) { port.write('s'); }
if (i == 68) { port.write('d'); }
}
}
}
​
void keyPressed() {
keys[keyCode] = true;
}
​
void keyReleased() {
keys[keyCode] = false;
}

Related

How to call a function and have it continue by pressing a key once?

I want the ball.move(); function in the code below to continue running after pressing space once. It only works if I continue pressing the space key.
void draw() {
if (start == true) {ball.move();}
}
void keyPressed() {
if (key == ' '){start = true;}
}
void keyReleased() {
if (key == ' ') {start = false;}
}
It's for a Pong game I am making and each time the ball hits the edge it is teleported to the center of the canvas. That´s when I want to be able to start the ball movement manually again.
Here is the whole code:
Ball ball;
Player player1;
Player player2;
int scorePlayer1 = 0;
int scorePlayer2 = 0;
PFont font;
boolean start;
void setup() {
size(1368,768);
frameRate(144);
noStroke();
ball = new Ball(width/2, height/2, 30);
player1 = new Player(15, height/2, 30, 150);
player2 = new Player(width-15, height/2, 30, 150);
ball.speedX = 10;
}
void draw() {
background(0);
textSize(40);
textAlign(CENTER);
font = loadFont("Arial-Black-48.vlw");
textFont(font);
ball.display();
if (start == true) {ball.move();}
player1.run();
player2.run();
//Score
if (ball.left() < 0) {
scorePlayer2 = scorePlayer2 + 1;
ball.x = width/2;
ball.y = height/2;
}
if (ball.right() > width) {
scorePlayer1 = scorePlayer1 +1;
ball.x = width/2;
ball.y = height/2;
}
text(scorePlayer1, width/2-75, 50);
text(scorePlayer2, width/2+75, 50);
//Collision
if (ball.top() < 0) {
ball.speedY = -ball.speedY;
}
if (ball.bottom() > height) {
ball.speedY = -ball.speedY;
}
if (ball.left() < player1.right() && ball.y > player1.top()-10 && ball.y < player1.bottom()+10) {
ball.speedX = -ball.speedX;
ball.speedY = map(ball.y - player1.y, -player1.h/2, player1.h/2, -5, 5);
}
if (ball.right() > player2.left() && ball.y > player2.top()-10 && ball.y < player2.bottom()+10) {
ball.speedX = -ball.speedX;
ball.speedY = map(ball.y - player2.y, -player2.h/2, player2.h/2, -5, 5);
}
if (player1.bottom() > height) {
player1.y = height-player1.h/2;
}
if (player1.top() < 0) {
player1.y = player1.h/2;
}
if (player2.bottom() > height) {
player2.y = height-player1.h/2;
}
if (player2.top() < 0) {
player2.y = player1.h/2;
}
}
//Movement
void keyPressed() {
player1.pressed((key == 'w' || key == 'W'), (key == 's' || key == 'S'));
player2.pressed((keyCode == UP), (keyCode == DOWN));
if (key == ' '){start = true;}
}
void keyReleased() {
player1.released((key == 'w' || key == 'W'), (key == 's' || key == 'S'));
player2.released((keyCode == UP), (keyCode == DOWN));
if (key == ' ') {start = false;}
}
class Ball {
float x;
float y;
float d;
float speedX;
float speedY;
color c;
//Constructor
Ball(float tempX, float tempY, float tempD){
x = tempX;
y = tempY;
d = tempD;
speedX = 0;
speedY = 0;
c = (255);
}
void display() {
fill(c);
ellipse(x,y,d,d);
}
void move() {
x = x + speedX;
y = y + speedY;
}
//Collision help
float top() {
return y-d/2;
}
float bottom() {
return y+d/2;
}
float left() {
return x-d/2;
}
float right() {
return x+d/2;
}
}
class Player {
float x, y;
float w, h;
float speedY = 0.0;
color c;
boolean moveUp = false, moveDown = false;
//Constructor
Player(float tempX, float tempY, float tempW, float tempH){
x = tempX;
y = tempY;
w = tempW;
h = tempH;
speedY = 0;
c = (255);
}
void run() {
display();
move();
}
void display() {
fill(c);
rect(x-w/2, y-h/2, w, h);
}
//Movement
void move() {
if (!moveUp && !moveDown) {speedY = speedY * 0.85;}
if (moveUp) {speedY -= 1;}
if (moveDown) {speedY += 1;}
speedY = max(-7.0, min(7.0, speedY));
y += speedY;
}
void pressed(boolean up, boolean down) {
if (up) {moveUp = true;}
if (down) {moveDown = true;}
}
void released(boolean up, boolean down) {
if (up) {moveUp = false;}
if (down) {moveDown = false;}
}
//Collision help
float top() {
return y-h/2;
}
float bottom() {
return y+h/2;
}
float left() {
return x-w/2;
}
float right() {
return x+w/2;
}
}
In the code below, you are setting start to true when the key is pressed and false when the press is done. You can simply remove the line that sets start to false when the key press is done and the ball will always move when the space is pressed.
//Movement
void keyPressed() {
player1.pressed((key == 'w' || key == 'W'), (key == 's' || key == 'S'));
player2.pressed((keyCode == UP), (keyCode == DOWN));
if (key == ' '){start = true;}
}
void keyReleased() {
player1.released((key == 'w' || key == 'W'), (key == 's' || key == 'S'));
player2.released((keyCode == UP), (keyCode == DOWN));
//if (key == ' ') {start = false;}
}
I suppose you want the ball to stop moving when space is pressed again. This can be done in your keyPressed method as well by toggling start instead of setting it to true. Something like if (key == ' '){start = !start;}
Your problem is that when you release the space bar, it sets the start field to false. Then when the next draw() method is called, it sees that start==false and so doesn't move the ball.
If you remove that line from the keyReleased method, then it should run correctly?

Smooth movement in processing?

I want this code to effectively increase the smoothness of the transition between directions (it only works with one key at a time) so that I can use multiple keys. The problem is that whenever I change direction the "Player" stops and then continues in the new direction. I want the "Player" to smoothly transition between directions without having to fully release the active key before pressing the new one.
Main code:
Ball ball;
Player player1;
Player player2;
void setup() {
size(1368,768);
frameRate(60);
noStroke();
ball = new Ball(width/2, height/2, 30);
player1 = new Player(0, height/2, 30, 150);
player2 = new Player(width-30, height/2, 30, 150);
ball.speedX = -10;
ball.speedY = random(-5,5);
}
void draw() {
background(0);
ball.display();
ball.move();
player1.run();
player2.run();
//Collision
if (ball.top() < 0) {
ball.speedY = -ball.speedY;
}
if (ball.bottom() > height) {
ball.speedY = -ball.speedY;
}
if (ball.left() < 0) {
ball.speedX = 0;
ball.speedY = 0;
}
if (ball.right() > width) {
ball.speedX = 0;
ball.speedY = 0;
}
}
void keyPressed() {
player1.pressed((key == 'w' || key == 'W'), (key == 's' || key == 'S'));
player2.pressed((keyCode == UP), (keyCode == DOWN));
}
void keyReleased() {
player1.released((key == 'w' || key == 'W'), (key == 's' || key == 'S'));
player2.released((keyCode == UP), (keyCode == DOWN));
}
Player class code:
class Player {
float x, y;
int dy = 0;
float w, h;
float speedY = 5;
color c;
//Constructor
Player(float tempX, float tempY, float tempW, float tempH){
x = tempX;
y = tempY;
w = tempW;
h = tempH;
speedY = 0;
c = (255);
}
void run() {
display();
move();
}
void display() {
fill(c);
rect(x, y-h/2, w, h);
}
void move() {
y += dy * speedY;
}
void pressed(boolean up, boolean down) {
if (up) {dy = -1;}
if (down) {dy = 1;}
}
void released(boolean up, boolean down) {
if (up) {dy = 0;}
if (down) {dy = 0;}
}
}
Thanks in advance!
Add 2 attributes move_up and move_down to the class Player and set the attributes in
pressed respectively released:
class Player {
// [...]
boolean move_up = false, move_down = false;
void pressed(boolean up, boolean down) {
if (up) {move_up = true;}
if (down) {move_down = true;}
}
void released(boolean up, boolean down) {
if (up) {move_up = false;}
if (down) {move_down = false;}
}
}
Change speedY dependent on the attributes in move. Continuously reduce the speed if neither move_up not move_down is set (speedY = speedY * 0.95;). That causes that the player smoothly slows down if no key is pressed. If move_up or move_down is pressed the slightly change the speed dependent on the desired direction. Restrict the speed to a certain interval (speedY = max(-5.0, min(5.0, speedY));):
class Player {
// [...]
void move() {
if (!move_up && !move_down) {speedY *= 0.95;}
if (move_up) {speedY -= 0.1;}
if (move_down) {speedY += 0.1;}
speedY = max(-5.0, min(5.0, speedY));
y += speedY;
}
// [...]
}
Class Player:
class Player {
float x, y;
float w, h;
float speedY = 0.0;
color c;
boolean move_up = false, move_down = false;
//Constructor
Player(float tempX, float tempY, float tempW, float tempH){
x = tempX;
y = tempY;
w = tempW;
h = tempH;
c = (255);
}
void run() {
display();
move();
}
void display() {
fill(c);
rect(x, y-h/2, w, h);
println(y);
}
void move() {
if (!move_up && !move_down) {speedY *= 0.95;}
if (move_up) {speedY -= 0.1;}
if (move_down) {speedY += 0.1;}
speedY = max(-5.0, min(5.0, speedY));
y += speedY;
}
void pressed(boolean up, boolean down) {
if (up) {move_up = true;}
if (down) {move_down = true;}
}
void released(boolean up, boolean down) {
if (up) {move_up = false;}
if (down) {move_down = false;}
}
}
If you want smooth transitions, you're going to have to give up "adding a fixed integer distance" in the key handlers, and instead track which keys are down or not, and then accelerating/decelerating your player every time draw() runs. As simple illustration:
Box box;
boolean[] active = new boolean[256];
void setup() {
size(500,500);
box = new Box(width/2, height/2);
}
void draw() {
pushStyle();
background(0);
box.update(active); // First, make the box update its velocity,
box.draw(); // then, tell the box to draw itself.
popStyle();
}
void keyPressed() { active[keyCode] = true; }
void keyReleased() { active[keyCode] = false; }
With a simple box class:
class Box {
final float MAX_SPEED = 1, ACCELERATION = 0.1, DECELERATION = 0.5;
float x, y;
float dx=0, dy=0;
Box(float _x, float _y) { x=_x; y=_y; }
void draw() {
// We first update our position, based on current speed,
x += dx;
y += dy;
// and then we draw ourselves.
noStroke();
fill(255);
rect(x,y,30,30);
}
void update(boolean[] keys) {
if (keys[38]) { dy -= ACCELERATION ; }
else if (keys[40]) { dy += ACCELERATION ; }
else { dy *= DECELERATION; }
if (keys[37]) { dx -= ACCELERATION ; }
else if (keys[39]) { dx += ACCELERATION ; }
else { dx *= DECELERATION; }
dx = constrain(dx, -MAX_SPEED, MAX_SPEED);
dy = constrain(dy, -MAX_SPEED, MAX_SPEED);
}
}
The important part here is the update code, which updates the box's x and y velocity such that if a directional key is currently pressed, we increase the speeed (dx/dy) in that direction. Importantly, if no keys are pressed we also dampen the speed to that it returns to 0.
Finally, to make sure we don't end up with infinite speed, we cap the maximum allowed velocity.

How do I create a restart button that shows in the button left corner while the game is running?

Our restart button is only appearing by itself. Our two tanks disappear when we run the game. We haven't coded the function of the button, we're just trying to figure out how to make the button appear in the lower left corner
We moved the code into the game object class, but it does not change anything
This is our game object class. The button is at the bottom.
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GameObject {
// Every moving object in our game is a separate GameObject. However, since there are different types of moving objects (eg. players and
// projectiles), each with their own variables and functions, we don't want to instantiate GameObjects (otherwise, we wouldn't be able
// to distinguish between a player and a projectile). Instead, we want to create derived (also known as child) classes to implement the
// separate functionality, and instantiate the derived/child classes instead. The purpose of this GameObject "parent" class is to
// provide the derived/child classes with a set of useful functions for handling physics interactions (eg. collisions with the terrain
// or the walls of the arena) between different GameObjects (eg. player/player, player/projectile, or even projectile/projectile). Note:
// depending on the features you implement, you may not end up using all of the functions provided in this class.
// Every GameObject contains its own velocity, position, size, and mass information (necessary for moving and handling physics
// interactions). We store this information in the GameObject class instead of the derived/child classes because every type of
// GameObject has the same set of velocity, position, size, and mass variables.
public double vX; // Velocity in the x direction. Positive if moving right. Negative if moving left.
public double vY; // Velocity in the y direction. Positive if moving down. Negative if moving up. Notice how it's flipped from the usual
// coordinate system in math!
public double posX; // Position along the x direction. Ranges from 0 (left edge) to maximumX (see below).
public double posY; // Position along the y direction. Ranges from 0 (top edge) to maximumY (see below).
public int width; // Width of the bounding box of the GameObject.
public int height; // Height of the bounding box of the GameObject.
public int mass; // Used in realistic physics collision calculations. Ignore it if you don't want to implement that feature.
public double radius; // Used for circular GameObjects only.
public int maximumX; // Maximum x position for a GameObject, equal to the arena width subtracted by the game object's width.
public int maximumY; // Maximum y position for a GameObject, equal to the arena height subtracted by the game object's height.
// Constructor. All derived (ie. child) classes call this constructor in their own constructors. The resulting derived/child class
// object can then call the other functions in this class.
public GameObject(int arenaWidth, int arenaHeight, double vX, double vY, double posX, double posY, int width, int height, int mass) {
this.vX = vX;
this.vY = vY;
this.posX = posX;
this.posY = posY;
this.width = width;
this.height = height;
this.mass = mass;
this.maximumX = arenaWidth - width;
this.maximumY = arenaHeight - height;
radius = Math.min(width, height) / 2.0;
}
// Note: No need to change this function since we're going to override it in the the child classes.
public boolean move(Map map, double translateX, double translateY) {
return false;
}
// Check if the calling GameObject currently intersects with the obj GameObject.
public boolean currentlyIntersects(GameObject obj) {
return (posX + width >= obj.posX && posY + height >= obj.posY && obj.posX + obj.width >= posX && obj.posY + obj.height >= posY);
}
// Check if the calling GameObject will intersect with the obj GameObject, after both have moved according to their velocities. A note
// of caution: what might go wrong if either player moves too fast?
public boolean willIntersect(GameObject obj) {
double nextX = posX + vX;
double nextY = posY + vY;
double nextObjX = obj.posX + obj.vX;
double nextObjY = obj.posY + obj.vY;
return (nextX + width >= nextObjX && nextY + height >= nextObjY && nextObjX + obj.width >= nextX && nextObjY + obj.height >= nextY);
}
// Clip the calling GameObject to within the arena's x bounds, if it has moved outside the arena along the x direction.
public boolean xClip() {
if (posX < 0) {
posX = 0;
return true;
} else if (posX > maximumX) {
posX = maximumX;
return true;
}
return false;
}
// Clip the calling GameObject to within the arena's y bounds, if it has moved outside the arena along the y direction.
public boolean yClip() {
if (posY < 0) {
posY = 0;
return true;
} else if (posY > maximumY) {
posY = maximumY;
return true;
}
return false;
}
// If the calling GameObject will move outside the arena along either direction (after moving according to its velocity), this function
// tells you which of the four edges of the arena it hit. If the calling GameObject will stay within the bounds of the arena, this
// function returns null.
public Direction hitEdgeDirection() {
if (posX + vX < 0) {
return Direction.LEFT;
} else if (posX + vX > maximumX) {
return Direction.RIGHT;
}
if (posY + vY < 0) {
return Direction.UP;
} else if (posY + vY > maximumY) {
return Direction.DOWN;
} else {
return null;
}
}
// If the calling GameObject will intersect with the "other" GameObject (after both move according to their velocities), this function
// tells you which of the four sides of the calling GameObject that the "other" GameObject hit. If the calling GameObject will not
// intersect with the "other" GameObject, this function returns null. Note: this function is great for figuring out when and where two
// rectangles intersect, but is it a good choice for handling circle/rectangle or circle/circle intersections?
public Direction hitObjectDirection(GameObject other) {
if (this.willIntersect(other)) {
double dx = other.posX + other.width / 2.0 + other.vX - (posX + width / 2.0 + vX);
double dy = other.posY + other.height / 2.0 + other.vY - (posY + height / 2.0 + vY);
double theta = Math.acos(dx / (Math.sqrt(dx * dx + dy * dy)));
double diagTheta = Math.atan2(height / 2.0, width / 2.0);
if (theta <= diagTheta) {
return Direction.RIGHT;
} else if (theta <= Math.PI - diagTheta) {
if (dy > 0) {
return Direction.DOWN;
} else {
return Direction.UP;
}
} else {
return Direction.LEFT;
}
} else {
return null;
}
}
// Change the calling GameObject's velocity (to simulate a "bouncing" effect) based on which direction it intersected another GameObject
// or the edge of the arena. If the passed in direction is null, this function does nothing (why is this a good idea?). This function is
// best used with the hitEdgeDirection and hitObjectDirection functions above.
public void bounce(Direction d) {
if (d == null) {
return;
}
// Note: We probably should use a "switch" statement here instead. But for pedagogical purposes it's left as a simple if/else
// conditional.
if (d == Direction.UP) {
vY = Math.abs(vY);
} else if (d == Direction.DOWN) {
vY = -Math.abs(vY);
} else if (d == Direction.LEFT) {
vX = Math.abs(vX);
} else if (d == Direction.RIGHT) {
vX = -Math.abs(vX);
}
}
// TODO: (Challenge!) If you want to implement realistic sphere-sphere collisions that take into account the laws of physics, do so in
// the function below.
public boolean bounceWith(GameObject otherObj, Map map, long frames, double[] actualVelocities) {
return false;
}
// Calculate the distance from (pointX, pointY)---perhaps representing the center of a circle---to the closest point on a rectangle
// bounded by minX (left), maxX (right), minY (top), and maxY (bottom). If the point is inside the rectangle, this function returns 0.
public double pointToRectSqrDist(double minX, double maxX, double minY, double maxY, double pointX, double pointY) {
double dx = Math.max(Math.max(minX - pointX, 0), pointX - maxX);
double dy = Math.max(Math.max(minY - pointY, 0), pointY - maxY);
return dx * dx + dy * dy;
}
// Rotate the point (x, y) "degrees" degrees around (centerX, centerY) in counterclockwise fashion, and return the resulting point in an
// array of length 2. If the returned array is "result", then (result[0], result[1]) is the final point.
public double[] rotatePoint(double centerX, double centerY, double degrees, double x, double y) {
double s = Math.sin(Math.toRadians(degrees));
double c = Math.cos(Math.toRadians(degrees));
x -= centerX;
y -= centerY;
double xNew = x * c - y * s;
double yNew = x * s + y * c;
double[] result = new double[2];
result[0] = xNew + centerX;
result[1] = yNew + centerY;
return result;
}
// Note: No need to change this function since we're going to override it in the the child classes.
public void draw(Graphics g) {
}
public static void main(String []args){
JButton b= new JButton("Reset");
JFrame f = new JFrame();
f.setSize(1200,800);
f.setVisible(true);
f.getDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p = new JPanel();
f.add(p);
p.add(b);
b.setSize(50,50);
b.setVisible(true);
b.setLocation(50, 50);
}
}
This is our arena class:
// TODO: Feel free to import any other libraries that you need.
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
#SuppressWarnings("serial")
public class Arena extends JPanel {
public int arenaWidth;
public int arenaHeight;
public Player player1;
public Player player2;
Timer timer;
public static int INTERVAL = 35;
public long lastTick;
// TODO: Add other variables to keep track of the game state or other game objects (eg. the map) that will be in your game. Don't forget
// to instantiate them in reset()!
// Constructor. Called inside Game.java for setting up the Arena on game start.
public Arena() {
// Create a timer that calls the tick() function every INTERVAL milliseconds. Every call of the tick() function is a "frame".
timer = new Timer(INTERVAL, new ActionListener() {
public void actionPerformed(ActionEvent e) {
tick();
}
});
lastTick = System.currentTimeMillis();
timer.start();
setFocusable(true);
// TODO: To recognize key presses, you need to fill in the following.
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent butthole) {
if (butthole.getKeyCode() == KeyEvent.VK_W) {
player1.isWPressed = true;
}
if (butthole.getKeyCode() == KeyEvent.VK_S) {
player1.isSPressed = true;
}
if (butthole.getKeyCode() == KeyEvent.VK_A) {
player1.isAPressed = true;
}
if (butthole.getKeyCode() == KeyEvent.VK_D) {
player1.isDPressed = true;
}
if (butthole.getKeyCode() == KeyEvent.VK_SPACE) {
player1.isSpacePressed = true;
}
if (butthole.getKeyCode() == KeyEvent.VK_UP) {
player2.isUpPressed = true;
}
if (butthole.getKeyCode() == KeyEvent.VK_DOWN) {
player2.isDownPressed = true;
}
if (butthole.getKeyCode() == KeyEvent.VK_LEFT) {
player2.isLeftPressed = true;
}
if (butthole.getKeyCode() == KeyEvent.VK_RIGHT) {
player2.isRightPressed = true;
}
if (butthole.getKeyCode() == KeyEvent.VK_ENTER) {
player2.isEnterPressed = true;
}
}
public void keyReleased(KeyEvent butthole) {
if (butthole.getKeyCode() == KeyEvent.VK_W) {
player1.isWPressed = false;
}
if (butthole.getKeyCode() == KeyEvent.VK_S) {
player1.isSPressed = false;
}
if (butthole.getKeyCode() == KeyEvent.VK_A) {
player1.isAPressed = false;
}
if (butthole.getKeyCode() == KeyEvent.VK_D) {
player1.isDPressed = false;
}
if (butthole.getKeyCode() == KeyEvent.VK_SPACE) {
player1.isSpacePressed = false;
}
if (butthole.getKeyCode() == KeyEvent.VK_UP) {
player2.isUpPressed = false;
}
if (butthole.getKeyCode() == KeyEvent.VK_DOWN) {
player2.isDownPressed = false;
}
if (butthole.getKeyCode() == KeyEvent.VK_LEFT) {
player2.isLeftPressed = false;
}
if (butthole.getKeyCode() == KeyEvent.VK_RIGHT) {
player2.isRightPressed = false;
}
if (butthole.getKeyCode() == KeyEvent.VK_ENTER) {
player2.isEnterPressed = false;
}
}
});
}
// Resets the game to its initial state.
public void reset() {
this.removeAll();
this.setBackground(Color.WHITE);
this.setOpaque(true);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
arenaWidth = (int) screenSize.getWidth();
arenaHeight = (int) screenSize.getHeight();
player1 = new Player(arenaWidth, arenaHeight, 100, 100, 1);
player2 = new Player(arenaWidth, arenaHeight, arenaWidth - Player.INIT_SIZE - 100, arenaHeight - Player.INIT_SIZE - 100, 2);
requestFocusInWindow();
}
// Function called once per "frame".
void tick() {
// While tick() should be called once every INTERVAL amount of time, there's no guarantee of that, particularly if you have a lot
// of background apps running. Thus, we need to calculate the time difference (timeDelta) between every two calls of the tick()
// function. Note: 1 divided by this difference is commonly known as the "frames per second", or fps.
long currentTime = System.currentTimeMillis();
long timeDelta = (currentTime - lastTick)/35;
lastTick = currentTime;
if ((player1.isWPressed && player1.isSPressed) ||
(!player1.isWPressed && !player1.isSPressed)) {
player1.vX = 0;
player1.vY = 0;
} else if (player1.isWPressed) {
//System.out.println("Up");
player1.vX = Math.cos(player1.RotationDegree*Math.PI/180)*player1.speed * timeDelta;
player1.vY = Math.sin(player1.RotationDegree*Math.PI/180)*player1.speed * timeDelta;
//player1.posY -= player1.speed*timeDelta;
// MOVE FORWARD
} else if (player1.isSPressed) {
//System.out.println("Down");
player1.vX = -Math.cos(player1.RotationDegree*Math.PI/180)*player1.speed * timeDelta;
player1.vY = -Math.sin(player1.RotationDegree*Math.PI/180)*player1.speed * timeDelta;
//player1.posY += player1.speed*timeDelta;
// MOVE BACKWARD;
}
if (player1.isAPressed) {
//System.out.println("Left");
player1.RotationDegree -= player1.rotateSpeed* timeDelta;
// MOVE BACKWARD;
}
if (player1.isDPressed) {
//System.out.parintln("Right");
player1.RotationDegree += player1.rotateSpeed* timeDelta;
// MOVE BACKWARD;
}
if(player1.RotationDegree > 360) {
player1.RotationDegree -= 360;
}
else if(player1.RotationDegree < 0) {
player1.RotationDegree += 360;
}
player1.move(null, player1.vX, player1.vY);
if ((player2.isUpPressed && player2.isDownPressed) ||
(!player2.isUpPressed && !player2.isDownPressed)) {
player2.vX = 0;
player2.vY = 0; }
else if (player2.isUpPressed) {
//System.out.println("Up");
player2.vX = Math.cos(player2.RotationDegree*Math.PI/180)*player2.speed* timeDelta;
player2.vY = Math.sin(player2.RotationDegree*Math.PI/180)*player2.speed* timeDelta;
//player2.posY -= player2.speed*timeDelta;
// MOVE FORWARD
}
else if (player2.isDownPressed) {
//System.out.println("Down");
player2.vX = -Math.cos(player2.RotationDegree*Math.PI/180)*player2.speed * timeDelta;
player2.vY = -Math.sin(player2.RotationDegree*Math.PI/180)*player2.speed * timeDelta;
//player2.posY += player2.speed*timeDelta;
// MOVE BACKWARD;
}
if (player2.isLeftPressed) {
//System.out.println("Left");
player2.RotationDegree -= player2.rotateSpeed*timeDelta;
// MOVE BACKWARD;
}
if (player2.isRightPressed) {
//System.out.println("Right");
player2.RotationDegree += player2.rotateSpeed*timeDelta;
// MOVE BACKWARD;
}
if(player2.RotationDegree > 360) {
player2.RotationDegree -= 360;
}
else if(player2.RotationDegree < 0) {
player2.RotationDegree += 360;
}
player2.move(null, player2.vX, player2.vY);
player1.currentReload -= timeDelta;
if (player1.currentReload <= 0)
;
{
if (player1.isSpacePressed) {
// create bullet and fire
BasicWeapon newBullet = new BasicWeapon(arenaWidth, arenaHeight, player1.posX + player1.radius, player1.posY + player1.radius, player1);
player1.bullets.add(newBullet);
player1.currentReload = player1.MaxReload;
}
}
ArrayList<PlayerProjectile> bulletsToDelete1 = new ArrayList<PlayerProjectile>();
for (int i = 0; i < player1.bullets.size(); i++) {
PlayerProjectile bulletToChange = player1.bullets.get(i);
bulletsToDelete1.add(bulletToChange);
}
player1.bullets.removeAll(bulletsToDelete1);
// TODO: Update the game state each frame. This can be broken into the following steps:
// Step 1: Handle the keys pressed during the last frame by both players and calculate their resulting velocities/orientations.
// Step 2: Move the players and detect/handle player/player collisions and player/terrain collisions.
// Step 3: Decide whether a bullet should be fired for each player and create new bullet(s) if so. Also, handle reload mechanics.
// Step 4: Move all bullets via their calculated velocities (up to bullet range). Handle bullet/player & bullet/terrain collisions.
// Step 5: Decide whether the game has ended. If so, stop the timer and print a message to the screen indicating who's the winner.
// Note: If you implement other features (eg. weapon swapping, damage counters...etc.), you might also need to add more steps above.
// Update the display: this function calls paintComponent as part of its execution.
repaint(); }
// TODO: Draw all of the objects in your game.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//AffineTransform at = AffineTransoform.getTranslateInstance();
player1.draw(g);
player2.draw(g);
}
// Returns the dimensions of the Arena (for properly resizing the JPanel on the screen).
#Override
public Dimension getPreferredSize() {
return new Dimension(arenaWidth, arenaHeight);
}
}
THIS IS OUR PLAYER CLASS
// TODO: Feel free to import any other libraries that you need.
//import java.*;
import java.awt.*;
import java.util.ArrayList;
//import javax.swing.*;
//import java.awt.event.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Player extends GameObject {
public static void main(String []args){
}
// TODO: Set these values as you see fit. However, which variables should you not set as negative numbers? Which variables should you
// not set as zero? Which v'ariables should you not set as a very large positive number? Why?
public static final int INIT_SIZE = 30;
public static final int INIT_MASS = 0;
public static final int INIT_DAMAGE = 0;
public static final double INIT_SPEED = 10;
public static final double INIT_ROTATE_SPEED = 10;
public static final int INIT_HEALTH = 100;
// Member variables of the player that you can change over the course of the game.
public int damage = INIT_DAMAGE;
public double speed = INIT_SPEED;
public double rotateSpeed = INIT_ROTATE_SPEED;
public int health = INIT_HEALTH;
public double orientation = 0;
public int id;
// TODO: You may need to set up extra variables to store the projectiles fired by this player, the reload status/time of this player,
// the key press/release status of this player, and any other player-related features you decide to implement. Make sure to update the
// constructor appropriately as well!
long currentReload = 0;
long MaxReload = BasicWeapon.INIT_RELOAD;
ArrayList<PlayerProjectile> bullets = new ArrayList<PlayerProjectile>();
double RotationDegree = 0;
boolean isWPressed = false;
boolean isSPressed = false;
boolean isAPressed = false;
boolean isDPressed = false;
boolean isSpacePressed = false;
boolean isEnterPressed = false;
boolean isUpPressed = false;
boolean isDownPressed = false;
boolean isLeftPressed = false;
boolean isRightPressed = false;
boolean isLeftCLickPressed = false;
// Constructor that calls the super (ie. parent) class's constructor and instantiates any other player-specific variables.
public Player(int arenaWidth, int arenaHeight, double startPosX, double startPosY, int id) {
super(arenaWidth, arenaHeight, 0, 0, startPosX, startPosY, INIT_SIZE, INIT_SIZE, INIT_MASS);
this.id = id;
}
// TODO: This function should move the player and handle any player-terrain interactions.
#Override
public boolean move(Map map, double translateX, double translateY) {
posX += translateX;
posY += translateY;
xClip();
yClip();
return false;
}
//UPDATE PLAYER POSTION HERE
//}
public void draw(Graphics g) {
// TODO: Draw the barrel(s) for the player here
double xChords[] = new double[4];
double YChords[] = new double[4];
xChords[0] = posX + 0.6 * width;
xChords[1] = posX + 0.6 * width;
xChords[2] = posX + 1.5 * width;
xChords[3] = posX + 1.5 * width;
YChords[0] = posY + 0.4 * height;
YChords[1] = posY + 0.5 * height;
YChords[2] = posY + 0.5 * height;
YChords[3] = posY + 0.4 * height;
double[] point0 = rotatePoint(posX + 0.5 * width, posY + 0.5 * height, RotationDegree, xChords[0], YChords[0]);
double[] point1 = rotatePoint(posX + 0.5 * width, posY + 0.5 * height, RotationDegree, xChords[1], YChords[1]);
double[] point2 = rotatePoint(posX + 0.5 * width, posY + 0.5 * height, RotationDegree, xChords[2], YChords[2]);
double[] point3 = rotatePoint(posX + 0.5 * width, posY + 0.5 * height, RotationDegree, xChords[3], YChords[3]);
int rotatedPointsX[] = new int[4];
int rotatedPointsY[] = new int[4];
rotatedPointsX[0] = (int)Math.round(point0[0]);
rotatedPointsX[1] = (int)Math.round(point1[0]);
rotatedPointsX[2] = (int)Math.round(point2[0]);
rotatedPointsX[3] = (int)Math.round(point3[0]);
rotatedPointsY[0] = (int)Math.round(point0[1]);
rotatedPointsY[1] = (int)Math.round(point1[1]);
rotatedPointsY[2] = (int)Math.round(point2[1]);
rotatedPointsY[3] = (int)Math.round(point3[1]);
g.drawPolygon(rotatedPointsX, rotatedPointsY, 4);
g.setColor(Color.BLACK);
g.fillPolygon(rotatedPointsX, rotatedPointsY, 4);
if (id == 1) {
g.setColor(new Color(255, 215, 0));
} else if (id == 2) {
g.setColor(Color.RED);
}
// Body
g.fillOval((int) posX, (int) posY, width, height);
g.setColor(Color.BLACK);
g.drawOval((int) posX, (int) posY, width, height);
// TODO: Draw the health bar for the player here.
}
}
Only the button appears, and player1 and player2 don't.
I think what you are trying to achieve is something like :
public static void main(String []args){
JButton button= new JButton("Reset");
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.add(button);
frame.add(panel, BorderLayout.NORTH);
frame.add(new Arena(), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
For future question please do not post so much code. See: don't just copy in your entire program!

Using Processing to Create Arcade of Games, after game is chosen. Won't draw, still runs. processing

Hi basically whenever I click p or b to run one of my games they run, but you can't see them as they don't draw over the main menu screen. These games do work if separated.
PImage pongImage, brickImage;
boolean mouseDown = false;
boolean [] keys = new boolean [128];
Ball ball;
Paddleb gamerPaddle;
static ArrayList<Brick> bricks = new ArrayList();
Puck puck;
Paddle one;//left
Paddle two;//right
int oneScore = 0;
int twoScore = 0;
int gameScreen = 0;
void setup() {
fullScreen();
ball = new Ball();//creating objects
gamerPaddle = new Paddleb();
puck = new Puck();//creating objects
one = new Paddle(true);
two = new Paddle(false);
}
void draw() {
menuPress();
if (gameScreen == 0) {
mainMenu();
}
if (gameScreen ==1) {
gamePong();
}
if (gameScreen == 2) {
gameBrick();
}
}
void keyReleased() {
keys[key] = false;
one.move(0);
two.move(0);
gamerPaddle.move(0);
}
void menuPress() {
if (keys['p'] == true) {
gameScreen = 1;
} else if (keys ['b'] == true) {
gameScreen =2;
} else {
gameScreen = 0;
}
}
void moves() {
if (keys['w'] == true) {
one.move(-10);
} else if (keys['s'] == true) {
one.move(10);
}
if (keys['i'] == true) {
two.move(-10);
} else if (keys['k'] == true) {
two.move(10);
}
if (keys['a'] == true) {
gamerPaddle.move(-10);
} else if (keys['d'] == true) {
gamerPaddle.move(10);
}
}
void keyPressed() {
keys[key] = true;
}
void drawBricks() {
for (int i = 0; i <= bricks.size() - 1; i++) {
fill(255);
rectMode(CORNER);
rect(bricks.get(i).x, bricks.get(i).y, bricks.get(i).s, bricks.get(i).s2);
}
}
void bricksSetup() {
rectMode(CORNER);
float s = 80;
float x = width/4;
float y = Brick.space;
while (y < height/2) {
while (x < width - width/4) {
bricks.add(new Brick(x, y, s, s));
x +=90;
}
x = width/4;
y +=90;
}
}
void mainMenu() {
float picsY = height/2;
float brickX = 2 * width/3;
float pongX = width/3 - width/4;
pongImage = loadImage("pong photo.PNG");
brickImage = loadImage("Brick breaker.PNG");
pongImage.resize(width/4, height/4);
brickImage.resize(width/4, height/4);
background(150);
fill(255);
textSize(72);
text("AhMen's Arcade", width/5 + width/7, height/3);
image(pongImage, pongX, picsY);
text("Pong", width/6, 4 * height/5 + height/50);
image(brickImage, brickX, picsY);
text("Brick Breaker", 2 * width/3 + width/100, 4 * height/5 + height/50);
}
void gamePong() {
background(0);
System.out.println("cat");
boolean gameEnding = false;
do {
background(0);
one.screen();//creates paddle
two.screen();
puck.position();
puck.sides();
puck.screen();
moves();
puck.checkHitOne(one);
puck.checkHitTwo(two);
one.refresh();//limits y movement and keeps it moving at speed of 0 to make stops and starts not noticible
two.refresh();
fill(255);
textSize(32);
text(oneScore, 20, 50);
text(twoScore, width-40, 50);
textMode(CENTER);
text("PONG", width/2-55, 50);
} while (gameEnding != true);
exit();
}
void gameBrick() {
System.out.println("ya");
background(0);
bricksSetup();
ball.position();
while (ball.y - ball.r > height || ball.p1Score >= ((bricks.size()-1)*50)) {
System.out.println('l');
background(0);
moves();
drawBricks();
ball.checkHitTwo(gamerPaddle);
ball.checkHitBrick();
gamerPaddle.screen();//creates paddle
gamerPaddle.refresh();//limits y movement and keeps it moving at speed of 0 to make stops and starts not noticible
gamerPaddle.refresh();
ball.position();
ball.sides();
ball.screen();
ball.score();
}
exit();
}
this is just the main method btw, I do have other methods for the objects. I am not sure why this doesn't work, but if someone that has an Idea what the issue may be please lmk.
The processing draw function does not run on a seperate thread. When you have a while loop, which doesn't end, the draw-function never gets executed anymore.
You have to use variables scoped to the processing file and not just a function and then modify those variables inside the functions you currently use as the game-loops.
For example, if you want a program where a ball moves to the right and returns to coordinate 0 after passing it, you would have to structure it like this:
Ball ball = new Ball();
void draw() {
playBallGame();
drawBall();
}
void playBallGame() {
if (ball.x > width) ball.x = 0;
ball.x++;
}
Not like this:
void draw() {
drawBall();
playBallGame();
}
void playBallGame() {
Ball ball = new Ball();
while (true) {
if (ball.x > width) ball.x = 0;
ball.x++;
}
}

Java - Detection collision in 2D tile game

I'm having fun to build a 2D tile game (without Slick2D of libgdx) and I'm working on collision since more than 15 hours. I think it's time to ask question. I searched a lot but none really responds what I searched for.
So, this is what it look like : 2D game capture (The dark tile are were the player can't walking in) and Another 2D game capture
The rectangle are were collision can happen. There, when they collide, it's still moving just enough to be lock in the tile. (can't do nothing anymore)
So, my class is called by the input handler, the update and the draw. Theses three by the "play" class. Who just update stuff. (Player.MoveUp(), Player.draw, ...)
The "WorldManager" is where the tiles are managed (the only 4 of them and the getType() is to look up if it's blocked (0 valid and 1 blocked)
The "LevelGeneration" is where level, position of tiles and their ID is
mapped (with a int[][]) (he is ok' it create map with ID and when I
show then they are all good).
The AssetManager is where I cut sprites sheets to transform then in BufferedImage
The tilesize is 50 and the player is 41x36.
I have a problem since I want to have a liberty of mouvements (4 sides to make 8 mouvements sides ) and the anchor point seem to be at upperleft side
So here is my class (without imports and packages):
public class Player {
public static double SPEED;
public static int WIDTH, HEIGHT;
public static float XPos, YPos;
public static float destXPos, destYPos;
public static BufferedImage presentImage;
public static int[] position;
public static boolean moving;
public static boolean movementlock;
public static int side; // 0 up 1 right 2 down 3 left
public static Rectangle p = null;
public static Rectangle e = null;
private static boolean mouvementlock;
private static boolean collision;
public static void CreateHero(){
// Valeurs de test
position = new int[2];
SPEED = 1;
XPos = destXPos = 100;
YPos = destYPos = 100;
presentImage = AssetManager.Player[0][0];
moving = false;
movementlock = false;
collision = false;
position[0] = (int) (XPos/WorldManager.TileSize);
position[1] = (int) (YPos/WorldManager.TileSize);
}
public static void MoveUp(){
side = 0;
destYPos -= SPEED;
moving = ValidateNextPosition();
}
public static void MoveRight(){
side = 1;
destXPos += SPEED;
moving = ValidateNextPosition();
}
public static void MoveDown(){
side = 2;
destYPos += SPEED;
moving = ValidateNextPosition();
}
public static void MoveLeft(){
side = 3;
destXPos -= SPEED;
moving = ValidateNextPosition();
}
static void updateMovement(){
if(moving == true && mouvementlock == false){
mouvementlock = true;
System.out.println("Mouvement");
System.out.println("X : " + XPos);
System.out.println("Y : " + YPos);
XPos = destXPos;
YPos = destYPos;
System.out.println("Xdest : " + destXPos);
System.out.println("Ydest : " + destYPos);
System.out.println("" + moving);
moving = false;
mouvementlock = false;}
else{
destXPos = XPos;
destYPos = YPos;
}
}
public static boolean ValidateNextPosition(){
if(moving) return false;
if(collision) return false;
p = new Rectangle((int) XPos, (int) YPos, presentImage.getWidth(null),presentImage.getHeight(null));
int tileid = 0;
boolean validate = true;
int destpos[] = new int[2];
double TileCollision[] = new double[2];
destpos[0] = (int) destXPos/WorldManager.TileSize;
destpos[1] = (int) destYPos/WorldManager.TileSize;
TileCollision[0] = 0;
TileCollision[1] = 0;
if(side == 0 && collision != true){
if(destpos[1] - 1 > 0){
tileid = LevelGenerator.getIdmap()[destpos[0]][destpos[1] - 1];
if(destYPos + 1 < 0 || WorldManager.Tuiles[tileid].getType() == 1 ){
destpos[1] -= 1;collision = true;}}
}
if(side == 1 && collision != true){
tileid = LevelGenerator.getIdmap()[destpos[0] + 1][destpos[1]];
if(destXPos + 1 < 0 || WorldManager.Tuiles[tileid].getType() == 1 ){
destpos[0] += 1;collision = true;}
}
if(side == 2 && collision != true){
tileid = LevelGenerator.getIdmap()[destpos[0]][destpos[1] + 1];
if(destYPos - 1 < 0 || WorldManager.Tuiles[tileid].getType() == 1 ){
destpos[1] += 1;collision = true;}
}
if(side == 3 && collision != true){
tileid = LevelGenerator.getIdmap()[destpos[0]][destpos[1]];
if(destXPos - 1 < 0 || WorldManager.Tuiles[tileid].getType() == 1 ){
/*destpos[0] -= 1*/;collision = true;}
}
if (collision == true){
TileCollision[0] = LevelGenerator.getPosmap()[destpos[0]][destpos[1]][0];
TileCollision[1] = LevelGenerator.getPosmap()[destpos[0]][destpos[1]][1];
e = new Rectangle((int) TileCollision[0], (int) TileCollision[1],WorldManager.TileSize,WorldManager.TileSize);}
if(e != null && p.intersects(e)){
validate = false;
System.out.println("collision");}
return validate;
}
public static void update() {
updateMovement();
}
public static void draw(Graphics2D g) {
g.drawImage(presentImage,(int) XPos,(int) YPos,presentImage.getWidth(null),presentImage.getWidth(null),null);
if(p != null){
g.setColor(Color.BLACK);
g.drawRect(p.x, p.y, p.width, p.height);}
if(e != null){
g.setColor(Color.BLACK);
g.drawRect(e.x, e.y, e.width, e.height);}
}
}
To resume,
The collision happen too late and the player get stuck in the blocked block.
Sometimes it pass through it since the (I suppose) the top left don't hit the block.
It can go out of the map without problems and then it crashed, but everything I tried keep crashing the game
Thank you very much and have a nice day
Hell'no
(P.S. : English is my third language, so ask me if you don't completely understand)
When collision gets set to true and your ValidateNextPosition method returns false, collision (and by extension your moving variable) can never be toggled again because of your if(collision) return false statement at the top.

Categories

Resources