How can I get an NPC to move randomly in XNA? - random

I basically want a character to walk in one direction for a while, stop, then go in another random direction. Right now my sprites look but don't move, randomly very quickly in all directions then wait and have another seizure. I will post the code I have so far in case that is useful.
class NPC: Mover
{
int movementTimer = 0;
public override Vector2 direction
{
get
{
Random rand = new Random();
int randDirection = rand.Next(8);
Vector2 inputDirection = Vector2.Zero;
if (movementTimer >= 50)
{
if (randDirection == 4)
{
inputDirection.X -= 1;
movingLeft = true;
}
else movingLeft = false;
if (randDirection == 1)
{
inputDirection.X += 1;
movingRight = true;
}
else movingRight = false;
if (randDirection == 2)
{
inputDirection.Y -= 1;
movingUp = true;
}
else movingUp = false;
if (randDirection == 3)
{
inputDirection.Y += 25;
movingDown = true;
}
else movingDown = false;
if (movementTimer >= 100)
{
movementTimer = 0;
}
}
return inputDirection * speed;
}
}
public NPC(Texture2D textureImage, Vector2 position,
Point frameSize, int collisionOffset, Point currentFrame, Point sheetSize,
Vector2 speed)
: base(textureImage, position, frameSize, collisionOffset, currentFrame,
sheetSize, speed)
{
}
public NPC(Texture2D textureImage, Vector2 position,
Point frameSize, int collisionOffset, Point currentFrame, Point sheetSize,
Vector2 speed, int millisecondsPerframe)
: base(textureImage, position, frameSize, collisionOffset, currentFrame,
sheetSize, speed, millisecondsPerframe)
{
}
public override void Update(GameTime gameTime, Rectangle clientBounds)
{
movementTimer++;
position += direction;
if (position.X < 0)
position.X = 0;
if (position.Y < 0)
position.Y = 0;
if (position.X > clientBounds.Width - frameSize.X)
position.X = clientBounds.Width - frameSize.X;
if (position.Y > clientBounds.Height - frameSize.Y)
position.Y = clientBounds.Height - frameSize.Y;
base.Update(gameTime, clientBounds);
}
}

How about you create a method to get a random direction:
Vector2 GetRandomDirection()
{
Random random = new Random();
int randomDirection = random.Next(8);
switch (randomDirection)
{
case 1:
return new Vector2(-1, 0);
case 2:
return new Vector2(1, 0);
case 3:
return new Vector2(0, -1);
case 4:
return new Vector2(0, 1);
//plus perhaps additional directions?
default:
return Vector2.Zero;
}
}
And then, when a set time has elapsed, you call that method to change the direction:
double totalElapsedSeconds = 0;
const double MovementChangeTimeSeconds = 2.0; //seconds
public override void Update(GameTime gameTime, Rectangle clientBounds)
{
totalElapsedSeconds += gameTime.ElapsedGameTime.TotalSeconds;
if (totalElapsedSeconds >= MovementChangeTimeSeconds)
{
totalElapsedSeconds -= MovementChangeTimeSeconds;
this.direction = GetRandomDirection();
}
position += direction;
//...
}
Use different code to detect which direction the NPC is moving (the booleans movingLeft, movingRight, etc.). Detect those values based on the direction vector. This way you don't have to assign redundant values.
enum MoveDirection
{
Up, Down, Left, Right, UpLeft, UpRight, DownLeft, DownRight, None
}
public MoveDirection GetMoveDirection(Vector2 direction)
{
if (direction.Y < 0)
{
if (direction.X < 0)
return MoveDirection.UpLeft;
else if (direction.X > 0)
return MoveDirection.UpRight;
else
return MoveDirection.Up;
}
else if (direction.Y > 0)
{
if (direction.X < 0)
return MoveDirection.DownLeft;
else if (direction.X > 0)
return MoveDirection.DownRight;
else
return MoveDirection.Down;
}
else
{
if (direction.X < 0)
return MoveDirection.Left;
else if (direction.X > 0)
return MoveDirection.Right;
else
return MoveDirection.None;
}
}
I presume this is used for rotating the sprite (or perhaps drawing a different one), so now you just need a switch:
public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
MoveDirection moveDirection = GetMoveDirection(this.direction);
switch(moveDirection)
{
case MoveDirection.Up:
//Draw up-facing sprite, or assign a value to a rotation variable.
break;
case MoveDirection.UpLeft:
//...
}
}

You can examine Platformer Starter Kit to know how enemies move.
As Microsoft discontinue the XNA development for Windows 8, he removes all links to download XNA 4 starter kits.
I upload original Platformer source code to bitbucket.
Here you can download original Platformer Starter Kit Source Code for XNA 4 http://vackup.blogspot.com.ar/2012/11/download-original-platformer-starter.html

Related

I'm trying to get pvectors used in the second frame, but nothing pops up anywhere for the pvector (Used circle too)

I can't see where the circle and not sure what's wrong with my code to make it so I can't see the circle with gravity that I coded. Wondering where I went wrong and what I could do to improve it. Can't seem to see what I've done wrong and I put the circle in gameState2 because I'm making the game in that gameState, gameState1 is for the introduction screen. I want to know why the circle won't appear when I use pvectors. If someone can please help me it would be greatly appreciated(this is an assignment for my class). I hope the comments help show the area in which I need help. (Also if someone could look over my code just for confirmation that I won't get bugs while trying to make the gravity.)
PImage background, backgroundGameState1, headbasketballbackground, player1, player2;
boolean moveRight, moveLeft, moveRight2, moveLeft2;
int canvasSizeX= 1000;
int canvasSizeY = 600;
int mainBackgroundX = 1000;
int mainBackgroundY = 600;
int gameState1 = 1;
int player1X = 100;
int player1Y = 200;
int player2X = 100;
int player2Y = 200;
int backgroundGameState1X= 1000;
int backgroundGameState1Y=600;
int time;
int player1MovmentX = 700;
int player2MovmentX = 100;
PVector Position = new PVector(250, 400);
PVector Velocity = new PVector(0, 0);
PVector Acceleration = new PVector(0, 5);
float elasticity = 0.8;
float airResistance = 0;
void setup() {
//size of canvas is 1000 on the X-axis by 600 on the y-axis
size(1000, 600);
//Loaded images and called them, also made sure to resize them in order to match the canvas size or to make program more asthetically pleasing
background = loadImage("headbasketballbackground.png");
background.resize(mainBackgroundX, mainBackgroundY);
backgroundGameState1 = loadImage("backgroundgamestate1.png");
backgroundGameState1.resize(backgroundGameState1X, backgroundGameState1Y);
player1 = loadImage("steph.png");
//resized image for the steph curry png
player1.resize(player1X, player1Y);
player2 = loadImage("kobe.png");
//resized the png
player2.resize(player2X, player2Y);
time=millis();
}
void draw() {
if (gameState1 == 1) {
background(backgroundGameState1);
if (millis() > time + 1000) {
text("Click On Space To Enter The Game!", 100, 100);
textSize(50);
// delay(3000); Used as a test to see how the delay would work and found it to be extremely slow so I increased it to 1000 milliseconds
}
drawGameState1();
}
if (gameState1 == 2) {
background(background);
image(player1, player1MovmentX, 300);
image(player2, player2MovmentX, 300);
}
if (player1MovmentX < 30) {
player1MovmentX = 40;
}
if (player1MovmentX > 930) {
player1MovmentX = 920;
}
if ( player2MovmentX < 30) {
player2MovmentX = 40;
}
if (player2MovmentX > 930) {
player2MovmentX = 920;
}
// if (gameState2 == 3) {
// text("Congrats you won!");
//}
}
void drawGameState1() {
}
void drawGameState2() {
drawBall();
checkIfBallHitEdge();
moveBall();
drawPlayer1Movment();
drawPlayer2Movment();
//drawBoundaries();
}
void drawGameState3() {
}
void drawPlayer1Movment() {
if (moveRight) {
player1MovmentX += 25;
}
if (moveLeft) {
player1MovmentX -= 25;
}
}
void drawPlayer2Movment() {
if (moveRight2) {
player2MovmentX += 25;
}
if (moveLeft) {
player2MovmentX -= 25;
}
}
//pvectors used here
void drawBall() {
ellipse(Position.x, Position.y, 30, 30);
}
void moveBall() {
Velocity = Velocity.add(Acceleration);
Velocity = Velocity.mult((1-airResistance)); // This slows the ball down a little bit each instant
Position = Position.add(Velocity);
}
//pvectors end here
void checkIfBallHitEdge() {
if (Position.x < 0 || Position.x > width) {
Velocity.x *= -1;
}
if (Position.y < 0) {
Velocity.y *= -1;
}
if (Position.y > height) { // Strikes the ground
Velocity.y *= -elasticity;
Position.y = height;
}
}
void keyPressed() {
if (gameState1 == 1) {
if (keyCode == 32) {
gameState1 = 2;
}
} else if (gameState1 == 2) {
if (keyCode == RIGHT) {
moveRight = true;
player1MovmentX += 25;
}
if (keyCode == LEFT) {
moveLeft = true;
player1MovmentX -= 25;
}
if (keyCode == 68) {
moveRight2 = true;
player2MovmentX += 25;
}
if (keyCode == 65) {
moveLeft2 = true;
player2MovmentX -= 25;
}
if (keyCode == UP) {
Velocity.y = -70;
}
}
}
void keyReleased() {
if (keyCode == RIGHT) {
moveRight = false;
}
if (keyCode == LEFT) {
moveLeft = false;
}
if (keyCode == 68) {
moveRight2 = false;
}
if (keyCode == 65) {
moveLeft2 = false;
}
}
I used the processing IDE for java.

I was wondering if someone could help me re-format my code to fix the loop I made

I was wondering what mistake I made in the line that is formatted like this "''" because I was wondering why my code wouldn't move back to the right to bounce back and forth between walls. I put the code that I need help in with single quotations. This is my frist time on stack, so any tips would be appreciated.
PImage invader, invader2, invader3, invader4, invader5, space, tank;
int tankX = 400;
PImage [] picArray = new PImage [7];
int invaderState = 2;
int timer = 0;
int lap = 0;
int [] alienXPos = {100, 180, 260, 340, 420, 500, 580, 660, 740, 820};
//had to add a few zeros on alienYPos otherwise the loop would bug out and wouldn't work
int[] alienYPos = {40, 140, 240, 340, 0, 0, 0, 0, 0, 0};
boolean moveLeft, moveRight;
int paddleSpeed = 3;
int gameState = 1;
String message1 = "Welcome to space invaders!";
String message2 = "Click space to start!";
boolean movingLeft, movingRight;
void setup() {
size(1000, 1000);
invader = loadImage("invader.jpg");
invader.resize(70, 50);
invader2 = loadImage("invader2.png");
invader2.resize(70, 50);
space = loadImage("space.png");
space.resize(1000, 1000);
tank = loadImage("tank.png");
tank.resize(150, 100);
}
void draw() {
background(space);
timer = millis();
if (timer-lap>800) {
lap = timer;
' **for (int m=0; m <10; m++) {
if (movingRight == false) {
alienXPos[m] += 40;
} else {
alienXPos[m] -= 40;
}
if (alienXPos [m] > 900 && movingRight == false) {
movingRight = true;
for (int l=0; l<10; l++) {
alienYPos[l] += 75;
println("movingleft : " + movingLeft);
println("Moving right : " + movingRight);
}
// if(movingLeft == false){
// alienXPos[m] -= 55;
//}
//else{
// alienXPos [m] += 40;
//}
if (movingLeft == false) {
//alienXPos[m] -=55;
} /*else {
alienXPos[m] ;
}*/
if (alienXPos[m] < 100 && movingLeft == true) {
movingLeft = false;
movingRight = true;
/*for (int l=0; l<10; l++) {
alienYPos[l] += 75;
}** '
println("movingLeft : " + movingLeft);
*/
}
}
}
/* if (alienXPos[m] > 0 && movingLeft == true) {
alienXPos[m] -= 55;
}*/
if (invaderState == 1) {
invaderState = 2;
} else {
invaderState = 1;
}
}
if (tankX > width) {
tankX = 0;
}
if (tankX < 0) {
tankX = 1000;
}
if (gameState == 1) {
drawGameState1();
} else if (gameState == 2) {
drawGameState2();
}
}
void drawGameState1() {
background(#222222);
fill(#000000);
textSize(36);
fill(130, 130, 130);
text(message1, 300, 450);
textSize(20);
text(message2, 430, 600);
}
void drawGameState2() {
background(space);
drawSpaceInvader1();
drawTank();
drawTankMovement();
}
void drawSpaceInvader1() {
for (int i=0; i< 10; i++) {
if (invaderState == 1) {
image(invader, alienXPos[i], alienYPos[0]);
image(invader, alienXPos[i], alienYPos[1]);
image(invader, alienXPos[i], alienYPos[2]);
image(invader, alienXPos[i], alienYPos[3]);
} else if (invaderState == 2) {
image(invader2, alienXPos[i], alienYPos[0]);
image(invader2, alienXPos[i], alienYPos[1]);
image(invader2, alienXPos[i], alienYPos[2]);
image(invader2, alienXPos[i], alienYPos[3]);
}
}
}
void drawTank() {
image(tank, tankX, 700);
}
void drawTankMovement() {
if (moveLeft) {
tankX -= 25;
}
if (moveRight) {
tankX += 25;
}
}
void keyPressed() {
if (gameState == 1) {
if (keyCode == 32) {
gameState = 2;
}
}
if (gameState == 2) {
if (keyCode == LEFT) {
moveLeft = true;
}
if (keyCode == RIGHT) {
moveRight = true;
}
}
}
void keyReleased() {
if (keyCode == LEFT) { // Left Key
moveLeft = false;
}
if (keyCode == RIGHT) { // Right Key
moveRight = false;
}
}
A few things:
Next time, please try and provide a minimal, reproducible example, you were almost there, but you forgot to attach the image files that you use to draw your game out. Running this code gave me errors saying I was missing a few files. I took the liberty of importing some nonsense image and reusing that as your missing assets.
Also missing from your answer is a more implicit title. I think you misunderstood the term "reformatting" code, as that generally refers to the formatting of code. To make your answer likely to be found by others with the same problem, please consider changing the title to what your question is actually about: You can't figure out why your code doesn't reverse the movement of your row of space invaders. Next time, please read this guide on how to write a proper question.
Now to answer your question:
I ran your code and noticed that movingLeft was false whilst movingRight was true. Yet your invaders seem to be running towards the left side of the screen. One of your mistakes was probably getting confused by these variables.
In your code you do
if (movingRight == false) {
alienXPos[m] += 40;
} else {
alienXPos[m] -= 40;
}
Which effectively does the opposite of what you want. In coordinates are oriented like this, assuming we have a 800x400 canvas:
So if you want your invaders to move right, you should be adding to the coordinates when the bool is true, not when it's false. Your logic which flips the invaders direction should be sound:
if (alienXPos[m] < 100 && movingLeft == true) {
movingLeft = false;
movingRight = true;
}
But since in your program due to the above logic error movingLeft is never true, this statement will never run.
One suggestion is that in the simple case of space invaders you don't really need to keep track of two seperate moving variables for each direction, after all, invaders either:
Move to the right
or
Move to the left
Thus you could ditch having two variables and just check, for example, movingRight. If that is true, the invaders should be moving to the right, and if it's false, they should be moving to the left.

Asteroids Game - Buggy Collision Detection

I am making an asteroid game using Processing 3.5.3. As you will see the collision detection is very buggy. When it detects collision between ship/asteroid sometimes it is greater than the asteroid size, sometimes it is smaller. Also, when the asteroids get smaller, the collision detect still seems to be calling the larger size asteroid. The collision between bullet and asteroid seems to only be a hit when the bullet is in the center of the asteroid.
Apologies for all the comments - they are required for my internal documentation.
Here is my code, it is broken up into classes.
Ship
class Ship {
PVector shipAcceleration;
PVector shipVelocity;
PVector shipPosition;
PShape shipShape;
float shipDirection;
int shipLastFire; //holds the time in millis that the last bullet was fired
int shipDelayTime;
Ship() {
shipAcceleration = new PVector();
shipVelocity = new PVector();
shipPosition = new PVector(width/2, height/2); // player starts in middle of screen
shipDirection = 0; // set to 0 to so "up" is a sense of direction
shipLastFire = 0;
shipDelayTime = 300;
keys = new boolean[5];
shipShape = createShape();
shipShape.beginShape();
shipShape.fill(255, 0, 0);
shipShape.vertex(0, -4);
shipShape.vertex(2, 0);
shipShape.vertex(2, 2);
shipShape.vertex(0, 1);
shipShape.vertex(-2, 2);
shipShape.vertex(-2, 0);
shipShape.vertex(0, -4);
shipShape.endShape();
}
void moveShip() {
shipShape.resetMatrix();
// reset.Matrix sourced from https://processing.org/reference/resetMatrix_.html
shipShape.rotate(radians(shipDirection)); // rotates ship
shape(shipShape, shipPosition.x, shipPosition.y, 10, 10);
}
void updateShip() {
// motion sourced from Chapter 22 of 'Processing: A programming handbook
// for visual designers and asrtists' by Casey Reas and Ben Fry
shipAcceleration.x = 0;
shipAcceleration.y = 0;
if (keys[0]) {
shipAcceleration.x = 0.5 * cos(radians(shipDirection) - PI/2);
shipAcceleration.y = 0.5 * sin(radians(shipDirection) - PI/2);
}
if (keys[1] && !keys[2])
{
shipDirection -= 5;
}
if (keys[2] && !keys[1])
{
shipDirection += 5;
}
shipVelocity.add(shipAcceleration);
// add sourced from https://processing.org/reference/PVector_add_.html
shipPosition.add(shipVelocity);
shipVelocity.mult(.95);
// mult sourced from https://processing.org/reference/PVector_mult_.html
shipPosition.x %= width;
if (shipPosition.x < -10)
{
shipPosition.x = width;
}
shipPosition.y %= height;
if (shipPosition.y < -10)
{
shipPosition.y = height;
}
if (keys[4]) {
if (millis() - shipLastFire > shipDelayTime) {
shipLastFire = millis();
fireBullet(shipPosition, shipVelocity, shipDirection);
}
}
}
}
Bullet
class Bullet {
PVector bulletPosition;
PVector bulletVelocity;
boolean bulletHidden; // used if lifespan is max and to help recycle
int bulletSize;
int bulletCreationTime;
int bulletLifespan; //the time in milli seconds that bullets last
int bulletSpeed;
Bullet() {
bulletHidden = true;
bulletSize = 5;
bulletPosition = new PVector();
bulletVelocity = new PVector();
bulletCreationTime = 0;
bulletLifespan = 3000;
bulletSpeed = 5;
}
void updateBullet() {
if (!bulletHidden) {
bulletPosition.add(bulletVelocity);
if (millis() - bulletCreationTime > bulletLifespan)
// millis sourced from https://processing.org/reference/millis_.html
{
bulletHidden = true;
}
bulletPosition.x %= width;
if (bulletPosition.x < -1)
{
bulletPosition.x = width;
}
bulletPosition.y %= height;
if (bulletPosition.y < -1)
{
bulletPosition.y = height;
}
}
}
void drawBullet() {
if (!bulletHidden) {
updateBullet();
ellipse(bulletPosition.x, bulletPosition.y, bulletSize, bulletSize);
}
}
void reset(PVector pos, PVector spe, float direct) {
bulletPosition = new PVector(pos.x + (20 * cos(radians(direct) - PI/2)), pos.y + (20 * sin(radians(direct) - PI/2)));
bulletVelocity.x = bulletSpeed * cos(radians(direct) - PI/2) + spe.x;
bulletVelocity.y = bulletSpeed * sin(radians(direct) - PI/2) + spe.y;
bulletCreationTime = millis();
bulletHidden = false;
}
}
Asteroid
class Asteroid {
float asteroidSize = (width/80*12);
float x;
float y;
float velocityX;
float velocityY;
PVector[] vertices = new PVector[8];
boolean active = true; //false after collision
int level = 1; // how many times has it been shot. Level 1 is not yet shot
Asteroid(float xPos, float yPos, int aLevel) {
if (xPos == 0 && yPos == 0) { //if begin level asteroids
x = random(width) ; // set random start positions
y = random (height);
} else { // if collision generating 2 smaller asteroids
x = xPos; // set from asteroid x, y
y = yPos;
}
velocityX = random(-2, 2);
velocityY = random(-2, 2);
level = aLevel; //sets asteroid level (how many times shot)
//create polygon. /aLevel generates smaller polygons with each collision.
vertices[0] = new PVector(random (width/80*3/aLevel), random(height/80*3/aLevel) );
vertices[1] = new PVector(random((width/80*4/aLevel), (width/80*8/aLevel)), random(height/80*3/aLevel) );
vertices[2] = new PVector(random((width/80*9/aLevel), (width/80*12/aLevel)), random(height/80*3/aLevel) );
vertices[3] = new PVector(random((width/80*9/aLevel), (width/80*12/aLevel)), random((height/80*4/aLevel), (height/80*8/aLevel)) );
vertices[4] = new PVector(random((width/80*9/aLevel), (width/80*12/aLevel)), random((height/80*9/aLevel), (height/80*12/aLevel)) );
vertices[5] = new PVector(random((width/80*4/aLevel), (width/80*8/aLevel)), random((height/80*9/aLevel), (height/80*12/aLevel)) );
vertices[6] = new PVector(random(width/80*3/aLevel), random((height/80*9/aLevel), (height/80*12/aLevel)) );
vertices[7] = new PVector(random(width/80*3/aLevel), random((height/80*4/aLevel), (height/80*8/aLevel)) );
}
void moveAsteroid() {
x = x + velocityX; //asteroids to move with a random velocity
y = y + velocityY;
if ( x < -1 * asteroidSize ) {
x = width + asteroidSize;
} //if off screen left, come back in right
if ( x > width + asteroidSize ) {
x = -1 * asteroidSize;
} // if off screen right, come back in left
if ( y < -1 * asteroidSize ) {
y = height + asteroidSize;
} //if off top of screen, come back in bottom
if ( y > height + asteroidSize ) {
y = -1 * asteroidSize ;
} //if off bottom of screen, come back in top
}
void asteroidDraw() {
if (active == false) { // If not active don't draw
return;
}
stroke(150);
fill(255);
// this was how I orginally coded. Have kept commented out for now, so I can see what I did, but will delete before submission.
/*beginShape();
vertex(vertices[0].x, vertices[0].y );
vertex(vertices[1].x, vertices[1].y );
vertex(vertices[2].x, vertices[2].y );
vertex(vertices[3].x, vertices[3].y );
vertex(vertices[4].x, vertices[4].y );
vertex(vertices[5].x, vertices[5].y );
vertex(vertices[6].x, vertices[6].y );
vertex(vertices[7].x, vertices[7].y );
endShape(CLOSE); */
beginShape();
for (PVector v : vertices) {
vertex(x+v.x, y+v.y);
}
endShape(CLOSE);
}
void manDown() {
active = false; //sets to in active so will stop drawing
// add 2 new asteroids to array
asteroids = (Asteroid[]) append( asteroids, new Asteroid( x+20, y+20, level + 1 ) ); // Appends asteroid to array. Changing level makes the asteroid smaller.
asteroids = (Asteroid[]) append( asteroids, new Asteroid( x-20, y-20, level + 1 ) ); // Appends two smaller asteroids to array.
}
}
Game Manager
class GameManager {
int scoreCount;
boolean gameState = true;
int lifeCount;
void newGame()
{
gameState = true; //sets game state to in play
scoreCount = 0; //set counter of flies killed to 0
lifeCount = 3;
}
void scoreUpdate()
{
textSize(width*3/100);
textAlign(LEFT);
fill(255);
text("Score " + scoreCount, (width*2/100), (height*4/100));
}
void lifeLost()
{
lifeCount = lifeCount - 1;
if (lifeCount <= 0) {
gameState = false;
gameOver();
}
}
void lifeUpdate()
{
textSize(height*3/100);
textAlign(LEFT);
fill(255);
text("Lives " + lifeCount, (width*2/100), ((height*4/100) + (height*3/100)) );
}
void gameOver()
{
background(0);
textSize(height*5/100);
textAlign(CENTER);
fill(255);
text("Game over", width/2, height/2.6);
//play again button
fill(255);
rect(((width/2)-(width/4)), (((height/2)- (height/12))), width/2, height/8);
fill(0);
text("Play Again", width/2, height/2);
//define area for play again button collision
if (mousePressed)
{
if (
(mouseX > width/4) &&
(mouseX < width/4 +width/2) &&
(mouseY > (height/2-height/10.5)) &&
(mouseY < ((height/2-height/10.5) + height/8))
)
{
setup(); //reset game
}
}
}
}
Main
Asteroid[] asteroids; //K Level 1 starts with 6, add 2 each level, 10 levels
Ship myShip;
GameManager gameManager;
ArrayList<Bullet> bullets;
// Array help sourced from chapter 28 of 'Processing: A programming handbook
// for visual designers and asrtists' by Casey Reas and Ben Fry
int bulletIndex; // used to recycle bullets
// index sourced from https://py.processing.org/reference/list_index.html
int startNum = 6; //K begin game with 6 asteroids in the level
boolean[] keys; // boolean for storing keypressed/released
void setup() {
size(800, 800);
gameManager = new GameManager();
gameManager.newGame();
bulletIndex = 0;
bullets = new ArrayList<Bullet>();
keys = new boolean[5];
myShip = new Ship();
asteroids = new Asteroid [startNum]; //K
for (int a = 0; a < startNum; a++) { //K create asteroids in array
asteroids[a] = new Asteroid(0, 0, 1); //K
}
for (int i = 0; i < 20; i++)
{
bullets.add(new Bullet()); // create bullets
}
}
void draw() {
background(0);
collisionDetect();
gameManager.gameState = true;
myShip.updateShip(); // E
myShip.moveShip(); // E
for (int a = 0; a < asteroids.length; a++) { //K for asteroids in array
asteroids[a].moveAsteroid(); //K
asteroids[a].asteroidDraw(); //K
}
gameManager.scoreUpdate();
gameManager.lifeUpdate();
for (int i = 0; i < bullets.size(); i++)
{
bullets.get(i).drawBullet(); // drawing bullets
}
}
void keyPressed() {
if (key == CODED) {
if (keyCode == UP)
keys[0] = true;
if (keyCode == LEFT)
keys[1] = true;
if (keyCode == RIGHT)
keys[2] = true;
if (keyCode == DOWN)
keys[3] = true;
} else {
if (key == 'w')
keys[0] = true;
if (key == 'a')
keys[1] = true;
if (key == 'd')
keys[2] = true;
if (key == 's')
keys[3] = true;
if (key == ' ')
keys[4] = true;
}
}
void keyReleased() {
if (key == CODED) {
if (keyCode == UP)
keys[0] = false;
if (keyCode == LEFT)
keys[1] = false;
if (keyCode == RIGHT)
keys[2] = false;
if (keyCode == DOWN)
keys[3] = false;
} else {
if (key == 'w')
keys[0] = false;
if (key == 'a')
keys[1] = false;
if (key == 'd')
keys[2] = false;
if (key == 's')
keys[3] = false;
if (key == ' ')
keys[4] = false;
}
}
void fireBullet(PVector pos, PVector spe, float dir) {
bullets.get(bulletIndex).reset(pos, spe, dir);
// set attributes of last used bullet
// get sourced from https://processing.org/reference/get_.html
bulletIndex++; //update index
bulletIndex %= bullets.size(); //keep index in range
}
void collisionDetect(){
Asteroid testHolder;
Bullet bulletHolder;
// asteroid and bullet objects to minimize creating new objects
for(int i = 0; i < asteroids.length; i++){
testHolder = asteroids[i];
if(dist(testHolder.x, testHolder.y, myShip.shipPosition.x,
myShip.shipPosition.y) < testHolder.asteroidSize)
// collision of player and the asteroid
{gameManager.gameOver();}
for(int j = 0; j < bullets.size(); j++){
bulletHolder = bullets.get(j);
// pull and store each bullet from the list
if(bulletHolder.bulletHidden){continue;}
// don't calculate anything if it is hidden
if(dist(testHolder.x, testHolder.y, bulletHolder.bulletPosition.x,
bulletHolder.bulletPosition.y) < testHolder.asteroidSize){
testHolder.manDown();
// used to detect collision and split if collided
bulletHolder.bulletHidden = true;
// hide the bullet so it won't go 'through' the asteroids
j++;
}
}
}
}
For the problem with the smaller asteroids, you need to make the asteroidSize dependent on the level. Currently they are all the same: float asteroidSize = (width/80*12);
As the to collision issue, the first thing is that you also have to take the size to the ship/bullet hitting the asteroid into account:
if(dist(testHolder.x, testHolder.y, myShip.shipPosition.x, myShip.shipPosition.y) < (testHolder.asteroidSize + myShip.size))
For clarity: size is in both cases the radius.
Second, there will always be some area's where this basic type of collision detection does not follow the visual, because your shapes are not circles. The randomness that you use for the asteroids does not help in that respect. A way to get more control over this is to define a couple of shapes per level, and pick one of those at random when creating an asteroid. This way you can tweak the shape/radius to make a good trade off between looks and function so it looks 'believable enough'.

Processing: Multiple bullets in top down shooter

I am trying to make a simple top down shooter. When the user presses W, A, S or D a 'bullet' (rectangle) will come out of the 'shooter'. With my code, you can only shoot one bullet per direction until it reaches the end of the screen. Is there a way to make it so they (the user) can shoot multiple bullets in one direction?
Here's my code:
package topdownshooter;
import processing.core.PApplet;
import processing.core.PImage;
public class TopDownShooter extends PApplet {
PImage shooter;
float shooterX = 400;
float shooterY = 300;
float u_bulletSpeed;
float l_bulletSpeed;
float d_bulletSpeed;
float r_bulletSpeed;
boolean shootUp = false;
boolean shootLeft = false;
boolean shootDown = false;
boolean shootRight = false;
public static void main(String[] args) {
PApplet.main("topdownshooter.TopDownShooter");
}
public void setup() {
shooter = loadImage("shooter.png");
}
public void settings() {
size(800, 600);
}
public void keyPressed() {
if(key == 'w') {
shootUp = true;
}
if(key == 'a') {
shootLeft = true;
}
if(key == 's') {
shootDown = true;
}
if(key == 'd') {
shootRight = true;
}
}
public void draw() {
background(206);
imageMode(CENTER);
image(shooter, shooterX, shooterY);
if(shootUp == true) {
rect(shooterX, shooterY-u_bulletSpeed, 5, 5);
u_bulletSpeed += 2;
if(u_bulletSpeed > 300) {
u_bulletSpeed = 0;
shootUp = false;
}
}
if(shootLeft == true) {
rect(shooterX-l_bulletSpeed, shooterY, 5, 5);
l_bulletSpeed += 2;
if(l_bulletSpeed > 400) {
l_bulletSpeed = 0;
shootLeft = false;
}
}
if(shootDown == true) {
rect(shooterX, shooterY+d_bulletSpeed, 5, 5);
d_bulletSpeed += 2;
if(d_bulletSpeed > 300) {
d_bulletSpeed = 0;
shootDown = false;
}
}
if(shootRight == true) {
rect(shooterX+r_bulletSpeed, shooterY, 5, 5);
r_bulletSpeed += 2;
if(r_bulletSpeed > 400) {
r_bulletSpeed = 0;
shootRight = false;
}
}
}
}
The language is processing and I am using the eclipse IDE.
Thanks!
Here's what I would do if I were you. First I'd encapsulate your bullet data into a class, like this:
class Bullet{
float x;
float y;
float xSpeed;
float ySpeed;
// you probably want a constructor here
void drawBullet(){
// bullet drawing code
}
}
Then I'd create an ArrayList that holds Bullet instances:
ArrayList<Bullet> bullets = new ArrayList<Bullet>();
To add a bullet, I'd create a new instance and add it to the ArrayList like this:
bullets.add(new Bullet(bulletX, bulletY));
Then to draw the bullets, I'd iterate over the ArrayList and call the corresponding function:
for(Bullet b : bullets){
b.drawBullet();
}
Shameless self-promotion:
Here is a tutorial on creating classes.
Here is a tutorial on using ArrayLists.

XNA SpriteSheet not working

I have added logic to show the Sprite animating but it's simply not showing on the screen. What am I doing wrong?
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch;
namespace MyXNAGame.Game_Classes
{
public class Player : Sprite
{
private int _frameCount = 6;
private int _frameIndex;
private Rectangle[] _frames;
public float _jumpVelocity = 12f;
public PlayerState _playerState;
public Rectangle BoundingBox
{
get { return new Rectangle {X = (int) Position.X, Y = (int) Position.Y, Height = Texture.Height, Width = Texture.Width}; }
}
public void Initialize()
{
_frames = new Rectangle[_frameCount];
int width = Texture.Width / _frameCount;
for (int i = 0; i < _frameCount; i++)
{
_frames[i] = new Rectangle(i*width, 0, width, Texture.Height);
}
}
public void Load(ContentManager contentManager, string assetName)
{
Texture = contentManager.Load<Texture2D>(assetName);
}
public void Update(GameTime gameTime)
{
while (TouchPanel.IsGestureAvailable)
{
GestureSample gestureSample = TouchPanel.ReadGesture();
if (gestureSample.GestureType == GestureType.Tap)
{
if (_playerState == PlayerState.Running)
{
_playerState = PlayerState.NormalJump;
}
}
if (gestureSample.GestureType == GestureType.Hold)
{
if (_playerState == PlayerState.Running)
{
_playerState = PlayerState.LongJump;
}
}
}
// NormalJump Logic
switch (_playerState)
{
case PlayerState.NormalJump:
Position.Y -= _jumpVelocity;
_jumpVelocity -= 0.5f;
if (_jumpVelocity == 0)
{
_playerState = PlayerState.Falling;
}
break;
case PlayerState.LongJump:
Position.Y -= _jumpVelocity;
_jumpVelocity -= 0.5f;
if (_jumpVelocity == 0)
{
_playerState = PlayerState.Falling;
}
break;
case PlayerState.Falling:
Position.Y += _jumpVelocity;
_jumpVelocity += 0.5f;
break;
case PlayerState.Running:
_frameIndex++;
if (_frameIndex > 5)
{
_frameIndex = 0;
}
break;
}
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Texture, Position, _frames[_frameIndex], Color.White, 0, new Vector2(0, 0), new Vector2(0, 0), SpriteEffects.None, 0);
}
}
}`
Can anyone see the obvious mistake? I am using WP7
I changed the 'Scale' parameter in the Draw() method from new Vector(0,0) to new Vector(1,1) as obviously, having a Scale of 0 will not show anything at all.

Resources