处理塔防游戏 - 塔攻击敌人

时间:2016-09-26 08:54:58

标签: java processing

我将保持这一点,我正在制作一个塔防游戏作为一个迷你项目,而我有一些空闲时间,我试图找出如何实现塔,以便能够拍摄他们进入时的enimies使用dist的范围,但我只是不知道如何实现一个使用enimies位置和塔位置的方法。我有一个CreepSprites和Towers的ArrayList

CreepSprite[] CreepSprites;
ArrayList<Tower> AllTowers = new ArrayList<Tower>();
ArrayList<Creep> AllCreeps = new ArrayList<Creep>();

如果有人可以给我一些指导,告诉我如何让塔能够拍摄那些很棒的Creeps,即使它没有摆脱它们,只要能够射击它们就会很棒

干杯

2 个答案:

答案 0 :(得分:6)

@ GoneUp的答案是正确的方向。在Processing中,您有一个名为PVector的类,它也提供了一个距离方法:dist()

PVector towerPos = new PVector(100, 100);
PVector enemyPos = new PVector(300, 300);

float towerAttackRadius = 200; 


void setup() {
  size(400, 400);
  rectMode(CENTER);
  strokeWeight(3);
}
void draw() {
  background(255);
  //draw tower
  noFill();

  //check range
  if(towerPos.dist(enemyPos) < towerAttackRadius){
    //tower engaged, draw in green
    stroke(0,192,0);
  }else{
    //tower in idle mode, draw in blue
    stroke(0, 0, 192);
  }

  //visualise tower attack radius
  //(towerAttackRadius * 2 -> radius * 2 = diameter (width/height))
  ellipse(towerPos.x, towerPos.y, towerAttackRadius * 2, towerAttackRadius * 2);
  //visualise tower
  rect(towerPos.x, towerPos.y, 30, 30);
  //draw enemy
  stroke(192, 0, 0);
  rect(enemyPos.x, enemyPos.y, 10, 10);
  //instructions
  fill(0);
  text("click and drag to move enemy",10,15);
}

void mouseDragged() {
  enemyPos.set(mouseX, mouseY);
}

我热烈推荐Daniel Shiffman的Nature of Code chapter on Vectors。 这是一个线性代数,但它非常有用,特别是对于那些值得早日掌握它的游戏。

例如,要射击子弹,你需要朝着方向发展。 你可以通过使用向量减法来做到这一点。

此外,您可能希望控制子弹在屏幕上向该方向移动的速度。这也可以通过规范化矢量来完成:保持它的方向,但是将它的大小减小到1.0:

vector normalization diagram from https://www.mathworks.com/matlabcentral/mlc-downloads/downloads/submissions/36248/versions/1/screenshot.png

在那之后,可以很容易地将矢量缩放(乘)到任何你想要的大小。

如果你知道塔的位置,你只需要添加这个缩放的速度来计算每帧应该绘制子弹的位置。

PVector已经具有同时执行这两项操作的功能:setMag()。 (设置mag是设定幅度(或矢量长度)的缩写)

它还提供heading()功能,方便锻炼角度。

以下是概念的基本证据:

PVector towerPos = new PVector(100, 100);
PVector enemyPos = new PVector(300, 300);

float towerAttackRadius = 300; 

ArrayList<Bullet> bullets = new ArrayList<Bullet>(); 

void setup() {
  size(400, 400);
  rectMode(CENTER);
  strokeWeight(3);
}
void draw() {
  background(255);

  //check if an enemy is within range using dist()
  //if the distance is smaller than the radius, attack!
  if(towerPos.dist(enemyPos) < towerAttackRadius){

    //hacky frame based counter: please use a millis() based timer instead
    //shoot every 30 frames
    if(frameCount % 30 == 0){
      shoot();
    }

  }

  //update bullets
  for(Bullet b : bullets) {
    b.update();
  }

  //draw tower
  noFill();
  stroke(0, 0, 192);
  //visualise tower attack radius
  //(towerAttackRadius * 2 -> radius * 2 = diameter (width/height))
  ellipse(towerPos.x, towerPos.y, towerAttackRadius * 2, towerAttackRadius * 2);
  //visualise tower
  rect(towerPos.x, towerPos.y, 30, 30);
  //draw enemy
  stroke(192, 0, 0);
  rect(enemyPos.x, enemyPos.y, 10, 10);
  //instructions
  fill(0);
  text("click and drag to move enemy",10,15);
}

void mouseDragged() {
  enemyPos.set(mouseX, mouseY);
}

void shoot(){
  //make a new Bullet pointing from the tower to the enemy
  Bullet b = new Bullet(towerPos.x,towerPos.y,enemyPos.x,enemyPos.y);
  //add it to the list of bullets (for updates)
  bullets.add(b);

  println(b);
}

class Bullet {
  //where does the bullet shoot from (and it's current position)
  PVector position = new PVector();
  //where does the bullet shooting towards
  PVector target = new PVector();
  //how fast does the bullet move on screen
  float speed = 1.2;
  //how large goes the bullet appear on screen
  float size = 10;

  //bullet velocity
  PVector velocity;

  Bullet(float startX,float startY, float endX, float endY) {
    position.set(startX,startY);
    target.set(endX,endY);

    //compute the difference vector (start to end) = direction
    velocity = PVector.sub(target,position);

    //normalize the vector = same direction but magnitude of 1 -> makes it easy to scale 
    //velocity.normalize();

    //scale by the speed to move on screen)
    //normalize + multiple = resize the vector -> same direction, different length
    //velocity.mult(speed);

    //or do both normalize and multiple using setMag()
    velocity.setMag(speed);  
  }
  void update() {
    //update position based on velocity (simply add velocity to current position)
    position.add(velocity);

    //render
    //compute rotation angle from velocity (implementation is 2D only btw)
    float angle = velocity.heading();
    pushMatrix();
    translate(position.x,position.y);
    rotate(angle);
    stroke(0);
    line(0,0,size,0);
    popMatrix();
  }

  String toString(){
    return position+"->"+target;
  }
}

preview

您实际上可以使用以下预览播放:

var towerPos,enemyPos;

var towerAttackRadius = 300; 

var bullets = [];

function setup() {
  createCanvas(400, 400);
  rectMode(CENTER);
  strokeWeight(3);
  
  
  towerPos = createVector(100, 100);
  enemyPos = createVector(300, 300);
}
function draw() {
  background(255);
  
  //check if an enemy is within range using dist()
  //if the distance is smaller than the radius, attack!
  if(towerPos.dist(enemyPos) < towerAttackRadius){
    
    //hacky frame based counter: please use a millis() based timer instead
    //shoot every 30 frames
    if(frameCount % 30 === 0){
      shoot();
    }
    
  }
  
  //update bullets
  for(var i = 0; i < bullets.length; i++) {
    bullets[i].update();
  }

  //draw tower
  noFill();
  stroke(0, 0, 192);
  //visualise tower attack radius 
  //(towerAttackRadius * 2 -> radius * 2 = diameter (width/height))
  ellipse(towerPos.x, towerPos.y, towerAttackRadius * 2, towerAttackRadius * 2);
  //visualise tower
  rect(towerPos.x, towerPos.y, 30, 30);
  //draw enemy
  stroke(192, 0, 0);
  rect(enemyPos.x, enemyPos.y, 10, 10);
  //instructions
  noStroke();
  fill(0);
  text("click and drag to move enemy",10,15);
}

function mouseDragged() {
  enemyPos.set(mouseX, mouseY);
}

function shoot(){
  //make a new Bullet pointing from the tower to the enemy
  var b = new Bullet(towerPos.x,towerPos.y,enemyPos.x,enemyPos.y);
  //add it to the list of bullets (for updates)
  bullets.push(b);
}

function Bullet(startX,startY,endX,endY) {
  //where does the bullet shoot from (and it's current position)
  this.position = createVector(startX,startY);
  //where does the bullet shooting towards
  this.target = createVector(endX,endY);
  //how fast does the bullet move on screen
  this.speed = 1.2;
  //how large goes the bullet appear on screen
  this.size = 10;

  //compute the difference vector (start to end) = direction
  this.velocity = p5.Vector.sub(this.target,this.position);
  //normalize the vector = same direction but magnitude of 1 -> makes it easy to scale 
  this.velocity.normalize();
  //scale by the speed to move on screen)
  //normalize + multiple = resize the vector -> same direction, different length
  this.velocity.mult(this.speed);
  
  this.update = function() {
    //update position based on velocity (simply add velocity to current position)
    this.position.add(this.velocity);
    
    //render
    //compute rotation angle from velocity (implementation is 2D only btw)
    var angle = this.velocity.heading();
    push();
    translate(this.position.x,this.position.y);
    rotate(angle);
    stroke(0);
    line(0,0,this.size,0);
    pop();
  }
  
}


//http://stackoverflow.com/questions/39698472/processing-tower-defence-game-towers-attacking-enemies
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.3/p5.min.js"></script>

与PVectors玩得开心! :) 一个重要的注意: 上面的代码是概念证明而没有优化。 从长远来看,有很多塔和敌人会慢下来。 一旦你获得了正确的数学/代码,你就可以开始做一些改进了:

  • 管理项目符号/实例(例如,重新使用屏幕外的项目符号 而不是一直创建新的实例)
  • 使用通过magSq()的平方距离和平方半径来加速计算

答案 1 :(得分:1)

您可以使用Point2D类来表示图形的x,y坐标。该课程有一个预先实施的distance method,可以根据半径进行检查。