Shooting Projectiles?

Hey!
So how could I do it that my tank shoot bullets in a straight line??
Is the bullet an object??

I want that the player could shoot endless bullets while moving and then it would be hundreds objects…
I will try it but you can tell me how you did it if you want ^^"

Yes the bullet would be an object. You need to keep track of the bullet’s location. I would just use a base sprite class (same as your player).

Once the bullet object is destroyed or reaches the boundaries of the program. Set it to null and ensure you don’t use it again. The JVM will garbage collect it.

Hmm, my suggestion would be to think about how you would do a single bullet first. Then, from there move on to how you would extend (Not talking about class inheritance) that to cover multiple bullets.

First, you need to think about how you want the bullets to move. You said they will be moving in straight lines and since you can ‘fire while moving’ that the game will be at least somewhat real-time, and as such the bullets will move with the game’s ‘tick’ instead of instant transition between where it’s fired and where it impacts.

What this means is that you’ll have to keep track of the bullet’s current position and it’s change in position.

Start by figuring out how you would do that and you’re a good distance into figuring out how you’ll do it for multiple bullets.

Some things you might want to think about when you’re making these decisions:

  1. That you will probably want to put some limit on the size of your battle field in a 'If the bullet moves outside of the area, it’s no longer movement is no longer calculated.
  2. That the bullet impact computation should be something of a ‘next’ step after you’ve got the bullet moving. If you’re new to programming, don’t bite off more than you can chew by attempting both in your first program.
  3. While it might seem like you should do this as a drawing/animation outputting the bullet’s coordinates will work better for testing than that, since before you attempt to do this, you should be able to at least calculate the location of the bullet after each tick on your own.

Seems not good to rely on GC. Remove it manually.

How do you propose to do that?

LoL my bad. I meant when you use for example List to store all entities, I’ll remove it rather set it null. With null object in my main List of entities, I have to check isNull every update and I don’t want.

I think the idea is that you null them then sweep the list into a new collection rather than incur the overhead of removing entities one at a time. They’re going to get gc’d either way, the question is how much unnecessary bookkeeping you’re doing on the collection.

So I’m doing this wrong all time! D:

Hmm, instead of nulling them, then sweeping the other into a list, what about just using two lists (Linked Lists of some sort, IE- Removing the first element is relatively low overhead wise). Every update, you remove the first element, do your computations on it. If it’s still a valid bullet, add it to the second list otherwise release it. Repeat until the first list is empty then swap them.

I’m not sure whether this will make good use of the GC (That mystical thing), but it seems better to me that doing a double-pass of the list of projectiles each time.

LinkedLists are slow as hell because they create an inner Entry object to keep references to the previous and next object. This is slow and causes lots of garbage collection if you remove lots of objects every frame.

I use ArrayList ::slight_smile:

Hmm, I guess it would depend on the implementation. If you made a bare-bones Linked List the removal/addition could probably be faster than that of the ArrayList. I would need to actually look at the ArrayList implementation, but if it does any sort of shifting operations to keep the array from having holes, then the Linked List would probably be faster.

Of course, it would depend on how many projectiles would be on the screen at once. There would be a point where nothing would be particularly efficient for a given form of efficiency.

Why not use queues? Sounds more like a queue when you say remove the first and if its valid add to then end. Pop, update, if alive, add to the end of the queue. You may not be able to get a specific object that is in the middle of the queue but most of the time I never want to do that.

Also, from my experience, running through arrays/collections that are about 1-5k in size is really not that expensive. Its the updating that will slow you down. Heck I really don’t think 25-50k is that massive. Now if you have many arrays that are all large and all need to be updated, sure it can get cumbersome but still. Anyways sorry for getting off topic.

The easiest way would be to use an object that has say an x and y value for the location and updating and a sprite/image that you will draw on the screen.
You can store it in an arraylist as its really easy to use. Then when its suppose to die just do remove(); Not most efficient but worry about making things faster when you have something to make faster.

You may also want some sort of collision method to see if its hitting a bad guy or if its off the screen. Maybe if your getting more complex give it some sort of life that you subtract from every update and when it reaches 0 remove it. This way you wont worry about it going off screen as much and maybe you can make bullets not go on forever but what fun would that be.

Ok I did it thanks!
If the player now keep pushing SPACE he shoots a straight beam of sprites xD"
I have to make a time interlay or something like that.

Here is some code for guns that shoot I worked up in the last couple of days:


public abstract class RangedWeapon extends Weapon {
	protected double maxRange;
	protected int clipSize;
	protected int clip;
	protected double projectileVelocity;
	
	protected double coolDown;	//number of seconds to reduce from maximum to minimum bloom
	protected double heatUp;	//number of bullets to reach maximum bloom
	
	protected double reloadtime;
	protected double reload;
	
	protected double direction;
	
	protected HashMap<Attack, ArrayList<Sprite>> hits;
	
	public RangedWeapon(Sprite owner){
		super(owner);
		hits = new HashMap<Attack, ArrayList<Sprite>>();
		this.clip = 0;
	}

	
	
	
	public double getProjectileVelocity(){
		return projectileVelocity;
	}
	
	@Override
	public void use(double mouseX, double mouseY) {
		if(!(atkTime < speed) && clip != 0){
			atkTime = 0;
			direction = Math.atan2(mouseX - getOwner().getAX(), mouseY - getOwner().getAY());
			attack();
			clip -= 1;
			//Send threat
			t.threaten(getOwner().getWorld(), 0);
			
			accuracyModifier += (accuracy/2)/heatUp;
			if(accuracyModifier > accuracy/2){
				accuracyModifier = accuracy/2;
			}
		} else if(clip == 0 && !(reload < reloadtime)){
			getOwner().requestReload(this);
		}

	}
	
	public void attack(){
		attacks.add(new RangedAttack(getOwner().getAX(), getOwner().getAY(), this, direction + (Math.random()*2 -1)*(accuracy/2 + accuracyModifier + getOwner().getMoveAccuPenalty()*accuracy/2)));
	}
	
	@Override
	public void tick(double d){
		if(reload < reloadtime){
			reload += d;
			if(reload >= reloadtime){
				clip = clipSize;
			}
		}
		if(accuracyModifier > 0){
			accuracyModifier -= (accuracy/2)/coolDown*d;
		} else {
			accuracyModifier = 0;
		}
			
		if(atkTime < speed){
			atkTime += d;
		}
//		System.out.println(attacks.size());
		for(Attack a : attacks){
			((RangedAttack) a).tick(d);
		}
	
		for(Attack a : attacks){
			CollisionReport cr = getOwner().getWorld().getCollisionReportForAttack(a);
			if(!hits.containsKey(a)){
				hits.put(a, new ArrayList<Sprite>());
			}
			for(Sprite s : cr.getCollidees()){
//				System.out.println(s);
				if(!hits.get(a).contains(s)){
					hits.get(a).add(s);
					s.receiveDamage(damage);
					s.receiveKnockBack(knockback, a.getX1(), a.getY1());
				}
			}
		}
	}

	
	public void removeAttack(RangedAttack a) {
//		System.out.println("removing attack");
		hits.remove(a);
		attacks.remove(a);
	}
	
	
	public void setReload(){
		reload = 0;
	}
	
	@Override
	public void reload(){
		getOwner().requestReload(this);
	}
	
	public Item equip(){
		if(reload < reloadtime){
			reload = 0;
		}
		return this;
	}
}

RangedAttacks essentially hold 2 points (origin and vector) and use Line2d.intersects(Rect2d) to test for collision with enemy hit boxes. Hope this helps you!

Thats a lot of unnececary work you’re doing there MunchGamer! Also instead of using ArrayLists, use lists! they are much easier to use once they are implemented once youve set them up.
also, what does this line of code do?


 t.threaten(getOwner().getWorld(), 0);

Ive never seen it before. threaten

That’s a part of the engine I’m making which sends threats to the world, ie when you fire a gun, the “sound” of you firing alerts nearby enemies to your position.

explains all. Thanks for clearing it up for me!

Just a quick question on this topic… when I am using bullets (or missiles/bombs or any similar object), I have an ArrayList and I add the object to the arraylist (and then in update/collision checks I just go through the ArrayList)

Once a bullet/missile/projectile hits something or goes out of bounds, I have been removing it from the ArrayList… only recently I have wondered, is this enough for the GC to collect it, as it is no longer referenced to? Or should I be manually setting the item to null before removing it?

Thanks
B