Change clicked object to another object

A

AutoLiMax

Guest
Hi, I'm trying to get an object at the location of a mouse click and then replace it with another object. The new object would be chosen based on what the previous object was.

So far I have this which destroys the object that's clicked and spawns another object in its place:
Code:
position_destroy (mouse_x-(mouse_x mod 16),mouse_y-(mouse_y mod 16));
instance_create (mouse_x-(mouse_x mod 16),mouse_y-(mouse_y mod 16),obj_dirt);
What I want to do is have an if statement that basically checks what the clicked object is and then decides what object to replace it with.

Something like:
Code:
if clicked object = (obj_grass)
   {
      instance_create (x,y),obj_dirt;
   }
if clicked object = (obj_dirt)
   {
      instance_create (x,y),obj_farmSoil;
   }
The above is just a thought. As I'm quite new to programming and game maker I'm not sure how I would go about writing it out as actual code.

Any one willing to lend a hand?

Thanks!
 
A

Aura

Guest
You can use a combination of instance_position() and object_index.

Code:
var _id = noone, obj;
with (instance_position(mouse_x-(mouse_x mod 16), mouse_y-(mouse_y mod 16), all)) {
   _id = id;
    obj = object_index;
}
if (_id != noone) {
   with (_id) {
      instance_destroy();
   }
   if (obj == obj_grass) {
      //...
   }
   else if (obj == obj_dirt) {
      //...
   }
}
If you want instances of certain objects to be taken under effect, create an object, set it as the parent of all the desired objects and use it in the place of all.
 

NazGhuL

NazTaiL
Hi. The instance_position function return an id. (or noone is no object)
Create an object and call it obj_parent_terrain. All your object (dirt, grass, etc) have to be the child of that object

if(instance_position( mouse_x,mouse_ y, obj_parent_terrain)
will check for all your terrain object and return an id or noone.

So it looks like:
(Run on a controller object)

Code:
var x1 = mouse_x-(mouse_x mod 16);
var y1 = mouse_y-(mouse_y mod 16);

var tmp_object = instance_position(x1 , y1, obj_parent_terrain);

if(tmp_object != noone)
{
var name = object_get_name(tmp_object.object_index);

    if(name == 'obj_dirt')
    {
    instance_create(x1, y1, obj_farmsoil);
    }
    else if(name == 'obj_grass')
    {
    instance_create(x1, y1, obj_dirt)
    }
    //etc...
  
    with(tmp_object)
    {
    instance_destroy();
    }
}
 
T

TDSrock

Guest
Hi. The instance_position function return an id. (or noone is no object)
Create an object and call it obj_parent_terrain. All your object (dirt, grass, etc) have to be the child of that object

if(instance_position( mouse_x,mouse_ y, obj_parent_terrain)
will check for all your terrain object and return an id or noone.

So it looks like:
(Run on a controller object)

Code:
var x1 = mouse_x-(mouse_x mod 16);
var y1 = mouse_y-(mouse_y mod 16);

var tmp_object = instance_position(x1 , y1, obj_parent_terrain);

if(tmp_object != noone)
{
var name = object_get_name(tmp_object.object_index);

    if(name == 'obj_dirt')
    {
    instance_create(x1, y1, obj_farmsoil);
    }
    else if(name == 'obj_grass')
    {
    instance_create(x1, y1, obj_dirt)
    }
    //etc...
  
    with(tmp_object)
    {
    instance_destroy();
    }
}
just quickly reading this as I cut through here.
This seems to be the solution however you'll want a switch instead of a series of if statements. Why? They are easier to add stuff too. And you can fall through cases easier which sometimes is nice.
The main reason a switch makes sense is because you are constantly checking the same variable.
so this:
Code:
if(name == 'obj_dirt')
    {
    instance_create(x1, y1, obj_farmsoil);
    }
    else if(name == 'obj_grass')
    {
    instance_create(x1, y1, obj_dirt)
    }
    //etc...
Would become this:
Code:
 switch(name)
    {
        case 'obj_dirt':
            instance_create(x1, y1, obj_farmsoil);
        break;
        case 'obj_grass':
            instance_create(x1, y1, obj_dirt)
        break;
        default:
            message_async("something went wrong with the switch");// note that I don't recall the actual async message command of the top of my head, so verify it's correct.
        break;
    }
Another benefit is that you have the default case, which would be the same as an else at the end of an if else section. But you could call the default and then have other cases fall into it as well.
 

NazGhuL

NazTaiL
Here is a better code, don't know why I put object get name... o_O

Code:
var x1 = mouse_x-(mouse_x mod 16);
var y1 = mouse_y-(mouse_y mod 16);

var tmp_object = instance_position(x1 , y1, obj_parent_terrain);

if(tmp_object != noone)
{
var tmp_obj_index = tmp_object.object_index;

    if(tmp_obj_index == obj_dirt)
    {
    instance_create(x1, y1, obj_farmsoil);
    }
    else if(tmp_obj_index == obj_grass)
    {
    instance_create(x1, y1, obj_dirt)
    }
    //etc...
 
    with(tmp_object)
    {
    instance_destroy();
    }
}
A switch is , of course, good but for examples for someone who just step in GM I prefer if statements.
@AutoLiMax , there is in fact hundreds of way to handle your situation. :)
 
A

AutoLiMax

Guest
Hi! Wow thanks for all the reply's. This is exactly what I'm looking for. I've going to get it to work using if's first and then if successful I'm going to try switches.

The only problem I have is with the obj_parent_terrain.

The thing is I'm using perlin noise to generate a map.
This is the script that adds the objects.
Code:
var waterLevel = 45;
var lightGrassLevel = 50;
var darkGrassLevelMin = 58;
var darkGrassLevelMax = 65;
var swampLevelMin = 66;
var swampLevelMax = 70;
var stoneLevelMin = 90;
var stoneLevelMax = 150;

for(var i = 0; i < width; i++)
{
    for(var j = 0; j < height; j++)
    {
        var zz = getPerlinNoise_2D(i,j,100);
        grid[# i,j] = zz;

        //Water
        if (zz < waterLevel)
        {
            instance_create(i*16,j*16,obj_ocean)
        }
        //Sand
        else if (zz >= waterLevel) and (zz <= lightGrassLevel)
        {
            instance_create(i*16,j*16,obj_sand)
        }
        //LightGrass
        else if (zz >= lightGrassLevel) and (zz <= darkGrassLevelMin)
        {
            instance_create(i*16,j*16,obj_lightGrass)
        }
        //DarkGrass
        else if (zz >= darkGrassLevelMin) and (zz <= darkGrassLevelMax)
        {
            instance_create(i*16,j*16,obj_darkGrass)
        }
        //Dirt
        else if (zz >= darkGrassLevelMax) and (zz <= swampLevelMin)
        {
            instance_create(i*16,j*16,obj_dirt)
        }
        //Swamp
        else if (zz >= swampLevelMin) and (zz <= swampLevelMax)
        {
            instance_create(i*16,j*16,obj_swamp)
        }
        //Stone
        else //if (zz >= stoneLevelMin) and (zz <= stoneLevelMax)
        {
            instance_create(i*16,j*16,obj_stone)
        }
    }
}

// This sorts out the autotile stuff
scr_executeAutoTile();
So the problem I'm having is that they are all separate objects and not parented.
Would it be possible to get the object at the location of the click and set it to a variable?

So if I clicked a location with dirt it would the set the tmp_object to obj_dirt.... Which would then check what to replace it with.

Thanks!
 
A

AutoLiMax

Guest
Oh ok, So when you say parent. Do you mean this?


I could just create an empty object and make it as a parent of all the terrain types?

Thanks
 
A

AutoLiMax

Guest
Never mind, I gave it a quick go and it seems to do the trick!

Thanks a lot.

I'll probably be back in a couple of minutes with more trouble :p
 
T

TDSrock

Guest
Never mind, I gave it a quick go and it seems to do the trick!

Thanks a lot.

I'll probably be back in a couple of minutes with more trouble :p
Something I will always ask people to do is to instead of asking if something will work, to test it. See what it does, and if it doesn't do what he/she expected to make a post saying what was tried, what the expected behavior is and what the real behavior is. ;)
 
Top