在 Processing 3 中需要子弹与敌人交互的帮助
Need assistance with bullet to enemy interaction in Processing 3
我正在为我的编程编写游戏class。这是一款飞机射击游戏,其他飞机以 "enemies" 的形式出现。发射的飞机发射小椭圆。我不知道如何将被击中的敌人从游戏中移除。我知道如何删除 "enemy" 但不知道如何在它们发生碰撞时实现这一点。这是我当前的代码。
ArrayList <Bullet> bullets = new ArrayList <Bullet> ();
ArrayList enemies;
PVector player, playerSpeed;
float maxSpeed = 3;
PImage jet;
PImage enemy;
PImage laser;
void setup() {
size(600, 600);
player = new PVector(300, 550);
playerSpeed = new PVector();
noCursor();
noStroke();
smooth();
String jeturl = "http://s1.postimg.org/dhe38w1rv/fighter_jet_md_20.png";
String enemyurl = "http://s29.postimg.org/cdaj0d7z7/fighter_jet_md_20.png";
String laserurl = "http://s13.postimg.org/fq00vsl37/red_Laser_Ray.png";
// Load image from a web server
jet = loadImage(jeturl, "png");
enemy = loadImage(enemyurl, "png");
laser = loadImage(laserurl, "png");
enemies = new ArrayList();
}
void draw() {
background(255);
player.add(playerSpeed);
//fill(255, 0, 0);
image(jet, player.x, player.y);
PVector mouse = new PVector(mouseX, mouseY);
fill(10);
ellipse(mouse.x, mouse.y, 5, 5);
if (frameCount%7==0 && mousePressed) {
PVector dir = PVector.sub(mouse, player);
dir.normalize();
dir.mult(maxSpeed*3);
Bullet b = new Bullet(player, dir);
bullets.add(b);
}
for(int i = enemies.size()-1; i>=0; i--) {
Enemy b = (Enemy) enemies.get(i);
b.move();
b.draw();
}
if (frameCount%50==0) {
enemies.add(new Enemy());
}
for (Bullet b : bullets) {
b.update();
b.display();
}
}
class Bullet extends PVector {
PVector vel;
Bullet(PVector loc, PVector vel) {
super(loc.x, loc.y);
this.vel = vel.get();
}
void update() {
add(vel);
}
void display() {
fill(0, 0, 255);
ellipse(x, y, 3, 3);
}
}
class Enemy {
float x, y;
Enemy() {
x = random(20, 580);
y = random(-20, -580);
}
void move() {
y = y + random(1,3);
}
void draw() {
image(enemy, x, y);
}
}
void keyPressed() {
if (keyCode == LEFT) {
playerSpeed.x = -maxSpeed;
}
if (keyCode == RIGHT) {
playerSpeed.x = maxSpeed;
}
}
void keyReleased() {
if (keyCode == LEFT || keyCode == RIGHT) {
playerSpeed.x = 0;
}
}
你需要给你的敌人添加一个监听器class。它应该是项目符号列表的无限循环。并且它应该具有当子弹坐标等于敌人坐标时执行 on_delete 回调的逻辑。我不是 Java 开发人员,但我会为您编写一些伪代码,为您指明正确的方向。需要做一个小改动,Enemy class 需要使用 enemy 数组中元素的索引进行初始化,以便可以通过回调正确销毁它。
Class Enemy (int idx){
void on_delete(){
enemies = ArrayUtils.removeElement(idx)};
void listen(){
cycle{
for(i=0; bullets.count()-1;i++){
bullet_x = bullets(i).getX
bullet_y = bullets(i).getY
if (bullet_x==x) && (bullet_y==y)
on_delete();
}
}
}
你知道子弹和敌人的坐标,因此你可以检查碰撞。有一个内置的 dist() 函数可以计算两点之间的欧氏距离。
虽然效率不高,也不准确,但您可以这样做:
ArrayList <Bullet> bullets = new ArrayList <Bullet> ();
ArrayList enemies;
PVector player, playerSpeed;
float maxSpeed = 3;
PImage jet;
PImage enemy;
PImage laser;
int lives = 3;
int score = 0;
void setup() {
size(600, 600);
player = new PVector(300, 550);
playerSpeed = new PVector();
noCursor();
noStroke();
smooth();
String jeturl = "http://s1.postimg.org/dhe38w1rv/fighter_jet_md_20.png";
String enemyurl = "http://s29.postimg.org/cdaj0d7z7/fighter_jet_md_20.png";
String laserurl = "http://s13.postimg.org/fq00vsl37/red_Laser_Ray.png";
// Load image from a web server
jet = loadImage(jeturl, "png");
enemy = loadImage(enemyurl, "png");
laser = loadImage(laserurl, "png");
enemies = new ArrayList();
}
void draw() {
background(255);
player.add(playerSpeed);
//fill(255, 0, 0);
image(jet, player.x, player.y);
PVector mouse = new PVector(mouseX, mouseY);
fill(10);
ellipse(mouse.x, mouse.y, 5, 5);
if (frameCount%7==0 && mousePressed) {
PVector dir = PVector.sub(mouse, player);
dir.normalize();
dir.mult(maxSpeed*3);
Bullet b = new Bullet(player, dir);
bullets.add(b);
}
for (int i = enemies.size ()-1; i>=0; i--) {
Enemy b = (Enemy) enemies.get(i);
b.move();
b.draw();
//check enemy to bullet collisions
//for each bullet
for(Bullet blt : bullets) {
//if the distance between the bullet and enemy is less than the enemy's width
if(dist(blt.x,blt.y,b.x,b.y) < enemy.width){
//remove the enemy
enemies.remove(b);
//optional, add score
score += 10;
}
}
//check enemy to player collision
if(dist(player.x,player.y,b.x,b.y) < jet.width){
enemies.remove(b);//remove current enely
//optional, update lives, reset score/game if needed
lives--;
println("player hit: " + lives + " lives left");
if(lives < 1){
println("Game Over!\nscore:" + score);
lives = 3;
score = 0;
}
}
}
if (frameCount%50==0) {
enemies.add(new Enemy());
}
for (Bullet b : bullets) {
b.update();
b.display();
}
}
class Bullet extends PVector {
PVector vel;
Bullet(PVector loc, PVector vel) {
super(loc.x, loc.y);
this.vel = vel.get();
}
void update() {
add(vel);
}
void display() {
fill(0, 0, 255);
ellipse(x, y, 3, 3);
}
}
class Enemy {
float x,y;
Enemy() {
x = random(20, 580);
y = random(-20, -580);
}
void move() {
y = y + random(1, 3);
}
void draw() {
image(enemy, x, y);
}
}
void keyPressed() {
if (keyCode == LEFT) {
playerSpeed.x = -maxSpeed;
}
if (keyCode == RIGHT) {
playerSpeed.x = maxSpeed;
}
}
void keyReleased() {
if (keyCode == LEFT || keyCode == RIGHT) {
playerSpeed.x = 0;
}
}
以上代码不准确的原因是它根据距离检查碰撞。想象一个围绕选中对象的圆圈。
如果您的对象是圆形,那将是完美的,但您的对象大多是矩形 (PImages)。
上述代码运行缓慢的原因与 dist() 函数的工作方式有关。想象一下屏幕上两个对象之间的一条线。从一个对象到另一个对象绘制两条直线,仅限于水平和垂直,将给出直角三角形的两侧,其中连接对象的原始线是斜线。要找到距离,您需要求解 hypothenuse,它是两侧相加的平方根。你不必太担心这个,因为 dist() 会为你做这个数学运算,但请记住它使用的是平方根,这在 CPU 上可能是昂贵的。
解决这个问题的一种方法是使用平方距离(并检查半径的平方),但这不会太准确。
另一种选择是进行简单的矩形边界检查。
您知道每个框 (PImage) 在屏幕上的位置以及每颗子弹的绘制位置,因此您可以判断每颗子弹是否在敌人体内。
同样,您可以检查两个矩形是否相交(更新坐标的玩家 PImage 和敌人 PImage)。
这是一个矩形相交的最小示例,它利用了 java.awt.Rectangle class(已经提供了相交检查):
import java.awt.Rectangle;
//based on jet image from previous code
int jetWidth = 20;
int jetHeight = 28;
Rectangle playerBox,enemyBox;
void setup(){
size(600, 600);
noFill();strokeWeight(3);
//bounding boxes
playerBox = new Rectangle(width / 2, height-jetHeight*2,jetWidth,jetHeight);
enemyBox = new Rectangle((int)random(width),-jetHeight,jetWidth,jetHeight);
}
void draw(){
//update enemy
enemyBox.y += 3;
//reset enemy position if out of screen
if(enemyBox.y > height) {
enemyBox.y = -jetHeight;
}
playerBox.x = (int)(mouseX - jetWidth * .5);
//check collision
if(playerBox.intersects(enemyBox)){
strokeWeight(10);
}else{
strokeWeight(3);
}
background(255);
stroke(192,0,0);
rect(enemyBox.x,enemyBox.y,enemyBox.width,enemyBox.height);
stroke(0,192,0);
rect(playerBox.x,playerBox.y,playerBox.width,playerBox.height);
}
如果您想要像素精度,可以利用您加载的图像的 Alpha 通道,并且:
- 初步做边界框测试
- 如果(且仅当)边界框相交,遍历一个图像的非透明像素以检查另一个图像的非透明像素)。 (如果你知道物体的方向,你可以用它来开始计算更接近可能碰撞的像素)
作为后续步骤,我建议实施基于边界框的碰撞检测。稍后您可能需要查看基本 state machines 以跟踪游戏状态(例如介绍屏幕、关卡 1、关卡 2...、游戏结束屏幕、高分屏幕等)
玩得开心! :)
我正在为我的编程编写游戏class。这是一款飞机射击游戏,其他飞机以 "enemies" 的形式出现。发射的飞机发射小椭圆。我不知道如何将被击中的敌人从游戏中移除。我知道如何删除 "enemy" 但不知道如何在它们发生碰撞时实现这一点。这是我当前的代码。
ArrayList <Bullet> bullets = new ArrayList <Bullet> ();
ArrayList enemies;
PVector player, playerSpeed;
float maxSpeed = 3;
PImage jet;
PImage enemy;
PImage laser;
void setup() {
size(600, 600);
player = new PVector(300, 550);
playerSpeed = new PVector();
noCursor();
noStroke();
smooth();
String jeturl = "http://s1.postimg.org/dhe38w1rv/fighter_jet_md_20.png";
String enemyurl = "http://s29.postimg.org/cdaj0d7z7/fighter_jet_md_20.png";
String laserurl = "http://s13.postimg.org/fq00vsl37/red_Laser_Ray.png";
// Load image from a web server
jet = loadImage(jeturl, "png");
enemy = loadImage(enemyurl, "png");
laser = loadImage(laserurl, "png");
enemies = new ArrayList();
}
void draw() {
background(255);
player.add(playerSpeed);
//fill(255, 0, 0);
image(jet, player.x, player.y);
PVector mouse = new PVector(mouseX, mouseY);
fill(10);
ellipse(mouse.x, mouse.y, 5, 5);
if (frameCount%7==0 && mousePressed) {
PVector dir = PVector.sub(mouse, player);
dir.normalize();
dir.mult(maxSpeed*3);
Bullet b = new Bullet(player, dir);
bullets.add(b);
}
for(int i = enemies.size()-1; i>=0; i--) {
Enemy b = (Enemy) enemies.get(i);
b.move();
b.draw();
}
if (frameCount%50==0) {
enemies.add(new Enemy());
}
for (Bullet b : bullets) {
b.update();
b.display();
}
}
class Bullet extends PVector {
PVector vel;
Bullet(PVector loc, PVector vel) {
super(loc.x, loc.y);
this.vel = vel.get();
}
void update() {
add(vel);
}
void display() {
fill(0, 0, 255);
ellipse(x, y, 3, 3);
}
}
class Enemy {
float x, y;
Enemy() {
x = random(20, 580);
y = random(-20, -580);
}
void move() {
y = y + random(1,3);
}
void draw() {
image(enemy, x, y);
}
}
void keyPressed() {
if (keyCode == LEFT) {
playerSpeed.x = -maxSpeed;
}
if (keyCode == RIGHT) {
playerSpeed.x = maxSpeed;
}
}
void keyReleased() {
if (keyCode == LEFT || keyCode == RIGHT) {
playerSpeed.x = 0;
}
}
你需要给你的敌人添加一个监听器class。它应该是项目符号列表的无限循环。并且它应该具有当子弹坐标等于敌人坐标时执行 on_delete 回调的逻辑。我不是 Java 开发人员,但我会为您编写一些伪代码,为您指明正确的方向。需要做一个小改动,Enemy class 需要使用 enemy 数组中元素的索引进行初始化,以便可以通过回调正确销毁它。
Class Enemy (int idx){
void on_delete(){
enemies = ArrayUtils.removeElement(idx)};
void listen(){
cycle{
for(i=0; bullets.count()-1;i++){
bullet_x = bullets(i).getX
bullet_y = bullets(i).getY
if (bullet_x==x) && (bullet_y==y)
on_delete();
}
}
}
你知道子弹和敌人的坐标,因此你可以检查碰撞。有一个内置的 dist() 函数可以计算两点之间的欧氏距离。
虽然效率不高,也不准确,但您可以这样做:
ArrayList <Bullet> bullets = new ArrayList <Bullet> ();
ArrayList enemies;
PVector player, playerSpeed;
float maxSpeed = 3;
PImage jet;
PImage enemy;
PImage laser;
int lives = 3;
int score = 0;
void setup() {
size(600, 600);
player = new PVector(300, 550);
playerSpeed = new PVector();
noCursor();
noStroke();
smooth();
String jeturl = "http://s1.postimg.org/dhe38w1rv/fighter_jet_md_20.png";
String enemyurl = "http://s29.postimg.org/cdaj0d7z7/fighter_jet_md_20.png";
String laserurl = "http://s13.postimg.org/fq00vsl37/red_Laser_Ray.png";
// Load image from a web server
jet = loadImage(jeturl, "png");
enemy = loadImage(enemyurl, "png");
laser = loadImage(laserurl, "png");
enemies = new ArrayList();
}
void draw() {
background(255);
player.add(playerSpeed);
//fill(255, 0, 0);
image(jet, player.x, player.y);
PVector mouse = new PVector(mouseX, mouseY);
fill(10);
ellipse(mouse.x, mouse.y, 5, 5);
if (frameCount%7==0 && mousePressed) {
PVector dir = PVector.sub(mouse, player);
dir.normalize();
dir.mult(maxSpeed*3);
Bullet b = new Bullet(player, dir);
bullets.add(b);
}
for (int i = enemies.size ()-1; i>=0; i--) {
Enemy b = (Enemy) enemies.get(i);
b.move();
b.draw();
//check enemy to bullet collisions
//for each bullet
for(Bullet blt : bullets) {
//if the distance between the bullet and enemy is less than the enemy's width
if(dist(blt.x,blt.y,b.x,b.y) < enemy.width){
//remove the enemy
enemies.remove(b);
//optional, add score
score += 10;
}
}
//check enemy to player collision
if(dist(player.x,player.y,b.x,b.y) < jet.width){
enemies.remove(b);//remove current enely
//optional, update lives, reset score/game if needed
lives--;
println("player hit: " + lives + " lives left");
if(lives < 1){
println("Game Over!\nscore:" + score);
lives = 3;
score = 0;
}
}
}
if (frameCount%50==0) {
enemies.add(new Enemy());
}
for (Bullet b : bullets) {
b.update();
b.display();
}
}
class Bullet extends PVector {
PVector vel;
Bullet(PVector loc, PVector vel) {
super(loc.x, loc.y);
this.vel = vel.get();
}
void update() {
add(vel);
}
void display() {
fill(0, 0, 255);
ellipse(x, y, 3, 3);
}
}
class Enemy {
float x,y;
Enemy() {
x = random(20, 580);
y = random(-20, -580);
}
void move() {
y = y + random(1, 3);
}
void draw() {
image(enemy, x, y);
}
}
void keyPressed() {
if (keyCode == LEFT) {
playerSpeed.x = -maxSpeed;
}
if (keyCode == RIGHT) {
playerSpeed.x = maxSpeed;
}
}
void keyReleased() {
if (keyCode == LEFT || keyCode == RIGHT) {
playerSpeed.x = 0;
}
}
以上代码不准确的原因是它根据距离检查碰撞。想象一个围绕选中对象的圆圈。 如果您的对象是圆形,那将是完美的,但您的对象大多是矩形 (PImages)。
上述代码运行缓慢的原因与 dist() 函数的工作方式有关。想象一下屏幕上两个对象之间的一条线。从一个对象到另一个对象绘制两条直线,仅限于水平和垂直,将给出直角三角形的两侧,其中连接对象的原始线是斜线。要找到距离,您需要求解 hypothenuse,它是两侧相加的平方根。你不必太担心这个,因为 dist() 会为你做这个数学运算,但请记住它使用的是平方根,这在 CPU 上可能是昂贵的。 解决这个问题的一种方法是使用平方距离(并检查半径的平方),但这不会太准确。
另一种选择是进行简单的矩形边界检查。 您知道每个框 (PImage) 在屏幕上的位置以及每颗子弹的绘制位置,因此您可以判断每颗子弹是否在敌人体内。 同样,您可以检查两个矩形是否相交(更新坐标的玩家 PImage 和敌人 PImage)。
这是一个矩形相交的最小示例,它利用了 java.awt.Rectangle class(已经提供了相交检查):
import java.awt.Rectangle;
//based on jet image from previous code
int jetWidth = 20;
int jetHeight = 28;
Rectangle playerBox,enemyBox;
void setup(){
size(600, 600);
noFill();strokeWeight(3);
//bounding boxes
playerBox = new Rectangle(width / 2, height-jetHeight*2,jetWidth,jetHeight);
enemyBox = new Rectangle((int)random(width),-jetHeight,jetWidth,jetHeight);
}
void draw(){
//update enemy
enemyBox.y += 3;
//reset enemy position if out of screen
if(enemyBox.y > height) {
enemyBox.y = -jetHeight;
}
playerBox.x = (int)(mouseX - jetWidth * .5);
//check collision
if(playerBox.intersects(enemyBox)){
strokeWeight(10);
}else{
strokeWeight(3);
}
background(255);
stroke(192,0,0);
rect(enemyBox.x,enemyBox.y,enemyBox.width,enemyBox.height);
stroke(0,192,0);
rect(playerBox.x,playerBox.y,playerBox.width,playerBox.height);
}
如果您想要像素精度,可以利用您加载的图像的 Alpha 通道,并且:
- 初步做边界框测试
- 如果(且仅当)边界框相交,遍历一个图像的非透明像素以检查另一个图像的非透明像素)。 (如果你知道物体的方向,你可以用它来开始计算更接近可能碰撞的像素)
作为后续步骤,我建议实施基于边界框的碰撞检测。稍后您可能需要查看基本 state machines 以跟踪游戏状态(例如介绍屏幕、关卡 1、关卡 2...、游戏结束屏幕、高分屏幕等)
玩得开心! :)