Gamemaker - destroy a specific instance without collision event - instance

I've just started using gamemaker studio 2 and I've been scratching my head over this one for a while.
I need to be able to destroy a specific instance of my enemy object without using the collision event. Here is my current code:
In my player object:
if (sprite_index = spr_player_attack_left) {
if (obj_enemy.x > x - 25 && obj_enemy.x < x) {
obj_enemy.hp--;
}
}
//detect right
if (sprite_index = spr_player_attack_right) {
if (obj_enemy.x < x + 25 && obj_enemy.x > x) {
obj_enemy.hp--;
}
}
//detect up
if (sprite_index = spr_player_attack_up) {
if (obj_enemy.y > y - 25 && obj_enemy.y < y) {
obj_enemy.hp--;
}
}
//detect down
if (sprite_index = spr_player_attack_up) {
if (obj_enemy.y < y + 25 && obj_enemy.y > y) {
obj_enemy.hp--;
}
}
And in my enemy object:
if (hp <= 0) {
var attacked = instance_find(obj_enemy, this.id);
instance_destroy(attacked);
}
Currently there is only one instance of the enemy in the room that registers an attack, and when I attack that instance, all instances are destroyed, while I only want one to be destroyed.
Thanks in advance for any help!

The reason this is happening is because you are using the object index, and not an index of a specific instance. When you do:
<object_index>.<object_property> eg. obj_enemy.hp
Two things can happen:
If there is one instance currently active in the game, then that
instance's variable will be referenced.
If there are two or more instances, then GameMaker can't tell which one you want to reference.
The offending code here are the if statements:
if (obj_enemy.x > x - 25 && obj_enemy.x < x) {
obj_enemy.hp--;
}
The way you can rewrite them is:
with (obj_enemy) {
if (x > other.x - 25 && x < other.x) hp--;
}
The same goes for all of the other if statements as well. The with keyword acts as a loop here. You can read it as "go through each instance of obj_enemy and do the code between { ... }". To reference the instance outside the with statement we use other(in this example, other will be the player).
And for the code in the enemy object, you don't have to use instance_find at all. Actually the this.id part is completely invalid, unless you define this as an instance variable before that code runs.
Anyways, the correct version would be:
if (hp <= 0) {
instance_destroy();
}
The instance_destroy function destroys the instance that is currently in scope(in GMS2 or GMS1 Early Access, you can pass it an additional id of the instance you wish to destroy).

Related

Hit detection implementation for Processing JS

I am having some trouble with programming hit detection in Processing.JS. I have tried to make a function that checks if something is touching an object and returns true and otherwise returns false. This is that here.
`Box.prototype.checkTouching = function(v){
if(v.position.x > this.position.x - this.width/2 && v.position <
this.position.x + this.width/2 && v.position.y > this.positon.y -
this.height/2 && v.position.y < this.position.y + this.height/2){
return true;
}else{
return false;
}
};`
I am implementing it by creating a new variable "b" in my draw function that holds the value the function returned then using an if statement to check if the value "b" is holding is true. Like so
var b = box3.checkTouching(mos);
if(b === true){
println("It works");
}
What should happen when the two objects touch is that a message saying "it works" gets printed in to the console. Unfortunately even when the object the function is running on is touching the object that is running it nothing happens. I have already checked to see if the logic works and it is valid so I know it has to be my implementation I just can not seem to find out what is wrong with my implementation. Can anyone tell what I am doing wrong? Full program here
You need to check whether the rectangles overlap. You'd do this by checking each side, like this:
if(rectOneRight > rectTwoLeft && rectOneLeft < rectTwoRight && rectOneBottom > rectTwoTop && rectOneTop < rectTwoBottom){
//collision
}
Shameless self-promotion: I've written a tutorial on collision detection in Processing (including rectangle-rectangle collision) available here.
To build on what Kevin posted, say I want to hover my mouse over a rectangle. processing has the built in variables mouseX, mouseY that return the coordinates of the mouse.
so I would check if the mouse X position was greater then the rect X pos, and less than the rect X pos + the rect width. the, do the same with the mouseY, rect Y and rect height
if (mouseX > rectXpos &&
mouseX < rectXpos + rectWidth &&
mouseY > rectYpos &&
mouseY < rectYpos + rectHeight) {
// the button is being hovered over
}

Hit Detection Implementation in Processing.JS

I am having some trouble with programming hit detection in Processing.JS. I have tried to make a function that checks if something is touching an object and returns true and otherwise returns false. This is that here.
Snake.prototype.checkTouching = function(v){
if(v.position.x > this.position.x - this.width/2 && v.position < this.position.x + this.width/2 && v.position.y > this.positon.y - this.height/2 && v.position.y < this.position.y + this.height/2){
return true;
}else{
return false;
}
};
I am implementing it by creating a new variable "b" in my draw function that holds the value the function returned then using an if statement to check if the value "b" is holding is true. Like so
var b = snakey.checkTouching(mos);
var restarts = 0;
if(b === true){
restarts += 1;
Program.restart();
}
unfortunately even when the object the function is running on is touching the object that is running it nothing happens. I have already checked to see if the logic works and it is valid so I know it has to be my implementation I just can not seem to find out what is wrong with my implementation. Can anyone tell what I am doing wrong? Full program here.Full Program

Bukkit countdown timer starts counting down infinite (2,1,-1,-2 etc)

So i got this problem when one - two+ players are online the countdown timer goes in minus like this 4,3,2,1,0 -1,-2,-3 etc.
Does anyone know how i can fix this, been struggling with it for quite a long time now :P
Here is my countdown class:
#Override
public void run() {
if (timeUntilStart == 0) {
if (!Game.canStart()) {
if(Bukkit.getOnlinePlayers().size() <= 2) {
plugin.restartCountdown();
ChatUtilities.broadcast(ChatColor.RED + "Not enough players to start. Countdown will");
ChatUtilities.broadcast(ChatColor.RED + "restart.");
for (Player p : Bukkit.getOnlinePlayers()) p.playSound(p.getLocation(), Sound.ENDERDRAGON_WINGS, 5, 1);
return;
}else{
if(Game.canStart()) {
if(Bukkit.getOnlinePlayers().size() >= 2) {
Game.start();
}
}
}
}
}
boolean broadcast = false;
for (Player p : Bukkit.getOnlinePlayers()) {
p.setLevel(timeUntilStart);
if (timeUntilStart < 11 || timeUntilStart == 120 ||timeUntilStart == 60 || timeUntilStart == 30) {
p.playSound(p.getLocation(), Sound.ORB_PICKUP, 5, 0);
if (timeUntilStart == 1) p.playSound(p.getLocation(), Sound.ORB_PICKUP, 5, 1);
broadcast = true;
}
}
if (broadcast) ChatUtilities.broadcast(String.valueOf(timeUntilStart) + " ยง6Seconds until the game starts!");{
}
{
timeUntilStart -= 1;
}
}
}
The only case in which your method returns and timeUtilStart is not decremented is
timeUntilStart == 0 && !Game.canStart() && Bukkit.getOnlinePlayers().size() <= 2
As defined by the first three if blocks in your code.
This explains why your countdown does not stop when you have 3 or more players around.
I believe this mistake happened because of messy {} blocks and indentation. Take a step back and closely read the code you wrote again and fix brackets as well as indentation.
Good formatting is not a pointless chore, it's an essential tool to help yourself understand what you already wrote.
Have you tried using the bukkit scheduler? People tend to forget that bukkit's API can handle countdowns very well. Just call the scheduler with this
myInteger = Bukkit's.getScheduler.scheduleSyncRepeatingTask(plugin, new runnable(), 0L, 20L)
Put your JavaPlugin extension class in as plugin, use runnable adding unimplemented methods, 0L is ticks before first run, 20L is ticks between each run.
Cancel the countdown like this
Bukkit's.getScheduler.cancelTask(myInteger)

Adding aging to boids simulation

I am working on expanding this sketch: http://www.openprocessing.org/sketch/11045
Trying to add aging to boids agents using frameCount.
I initialise ArrayList with age inbuilt:
boids = new ArrayList();
for (int i = 0; i < boidNum; i++) {
Agent boid = new Agent(random(width), random(height), 1, round(frameCount + random(300, 400)));
boids.add(boid);
}
Then retrieve it :
Agent(float posX, float posY, int t, int a) {
mass = 5.0;
location = new PVector(posX, posY);
vel = new PVector(random(-5,5), random(-5, 5));
acc = new PVector();
type = t;
wdelta = 0.0;
action = 0;
age = a;
}
I want to use something like this for the living cycle :
if (frameCount != age) {
age = age - 1;
}
if (frameCount == age) {
boids.remove(this);
}
But I'm not sure where in the code I should put it.
Also is this the best way to do it, or am I overcomplicating things?
Update:
I wrote a new method:
void boid(ArrayList boids) {
for (int i = 0; i < boids.size(); i++) {
if (frameCount >= age) {
boids.remove(this);
}
}
}
which is being called from:
void steer(ArrayList boids, ArrayList predators, ArrayList landscape) {
if (type == 1) boid(boids); ...
It sounds like you would want to put that code in the Agent class, after you do the updating and drawing of the Agent- taking a quick look at the code, that's probably the run() function in the Agent class.
But I'm not totally sure why you're comparing each Agent's age with the frameCount. The frameCount variable just tells you how long the sketch has been running. You if statement kills any birds that have the same age as the sketch, which doesn't make any sense.
Instead, you need to have two variables in your Agent class: the age variable that starts at 0 and increments by one each frame, and a maxAge variable that stores the age at which the Agent should be removed.
If you want some friendly advice though, I'd really recommend starting over from scratch with your own code instead of trying to modify an existing one, especially if you aren't really sure how the code works yet. It might seem like you're saving time by using existing code, but if you don't really know how code works yet, you'll definitely save yourself a bunch of headaches by writing it yourself. Up to you though.

Actionscript 3: How to make movieclip variables work with variables on stage (Healthbar Help)

I am totally new at this whole programming thing, and I really need help. So basically, I'm trying to make a healthbar that will increase or decrease depending on what button is clicked. I made a healthbar movieclip with 101 frames (I included zero) and put this in the actionscript layer of the movieclip:
var health:Number = 0;
if(health == 0)
{
gotoAndStop("1")
}
if(health == 1)
{
gotoAndStop("2")
}
if(health == 2)
{
gotoAndStop("3")
}
and on and on like so. Basically, on the stage itself, I have a button called fortyfiveup_btn that is commanded to do this:
var health:Number = 0;
fortyfiveup_btn.addEventListener(MouseEvent.CLICK, fortyfiveupClick);
function fortyfiveupClick(event:MouseEvent):void{
health = health+45
}
I quickly realized that both health variables, the one for the button and the one for the healthbar will not interact. How can I make it so if the button is clicked, the health goes to the relevant frame or percentage?
Thanks for any answers, and I appreciate all the help I can get :)
If the answer == yes to my comment you should do this:
You need to give the movieclip an instancename (perhaps lifebar) and from stage you can access the health inside the "lifebar" with lifebar.health.
So you need this inside your stage:
//You can delete the var health:Number = 0;
fortyfiveup_btn.addEventListener(MouseEvent.CLICK, fortyfiveupClick);
function fortyfiveupClick(event:MouseEvent):void{
//You can write this, too: lifebar.health += 45;
lifebar.health = lifebar.health+45;
}
You can even optimize your lifebar script, don't use 101 times the if(health == x) you can use this, too:
gotoAndStop(health + 1);
(I think this is inside an ENTER_FRAME event?)
EDIT:
Some error countermeasures:
//Don't let health decrease below 0
if(health < 0) health = 0;
//And don't above 100
else if(health > 100) health = 100;
gotoAndStop(health + 1);
Use int instead of Number when you don't use decimal numbers and uint when you don't use negative integers (this bugs when the number can drop under 0, so for your health we take int):
health:int = 0;