• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Legacy GM Making a The Legend of Zelda Tektite Enemy

H

HenrikoNumberOne

Guest
Hi! I'm trying to recreate the "Tektite" enemy from The Legend of Zelda in Game Maker Studio. I've tried for quite a while now but I can't really get it to work.

Tektites are the spider-like enemies in Zelda, and they jump around randomly, and sometimes towards the player, often in groups. They first wait for a bit, and then takes a big leap - and continues to repeat this pattern until the player is dead or goes off screen. Tektites are not bound by any collision either, which is nice. However, when I tried making this enemy myself I got stuck. All it has to do is switch between jumping and not doing anything, but I'm pretty new to this and any help would be much appreciated.

Video of a tektite in the real game, this is the behavior I'm trying to mimic;

Thanks in advance.
- Henriko
 

NicoFIDI

Member
Hi :D
due the fact that you didnt provide code, i wont atack you with code, but some things that you need are:
1- alarms with random trigger time (to make them jump when they are in idle state).
2- idle state and jumping state
3- to make them jump like that you need to make them go up and down like when they jump horizontaly, and at the same time move to the desinated location so they reach it at the same time they land (sounds harder than it is).
 
R

Remixful

Guest
This is how I'd go about doing this. Two states. Idle, jumping.
When idle - set alarm to random interval.
When the alarm is triggered - the enemy is set to the jumping state and a nearby location is randomly chosen as a destination.
In the step event, if the enemy is jumping, move towards the destination. You would only have to figure out the archlike movement though.

(Ninja'd x.x)
 
H

HenrikoNumberOne

Guest
This is how I'd go about doing this. Two states. Idle, jumping.
When idle - set alarm to random interval.
When the alarm is triggered - the enemy is set to the jumping state and a nearby location is randomly chosen as a destination.
In the step event, if the enemy is jumping, move towards the destination. You would only have to figure out the archlike movement though.

(Ninja'd x.x)
Alright so I did something to what you described, and it works alright! The only issue I'm having is making the enemy select a random nearby (relative) spot. Is there a function for that?

Thanks in advance.
- Henriko
 
Last edited by a moderator:
H

HenrikoNumberOne

Guest
I tried using that, but the enemies keep jumping to 0,0 and not randomx, randomy. I don't know what I'm doing wrong here...

Code:
if (state == "JUMPING") {
    choose(move_towards_point(randomx, randomy, move_speed));
}

if timer >= 150 {
    state = choose("IDLE", "JUMPING", "JUMPING")
    timer = 0;
        }

if (state == "JUMPING") {
randomx = random_range(self.x-200, self.x+200);
randomy = random_range(self.y-200, self.y+200);
}
 

NicoFIDI

Member
i try to keep the code as similar as your's
Code:
var jump_duration = 30;
var jump_radius = 200;
var max_idle_time = 30;

timer++;

if (timer >= jump_duration + cooldown) {
    timer = 0;
    arc_offset = 0;
    state = "JUMPING";
    cooldown = 1+irandom(max_idle_time);
   
    originX = x;
    originY = y;
   
    destinationX = random_range(self.x-jump_radius, self.x+jump_radius);
    destinationY = random_range(self.y-jump_radius, self.y+jump_radius);
    move_speed = point_distance(x,y,destinationX,destinationY);
}

if (state = "JUMPING") {
    var arc_delta = sign (timer - jump_duration/2);
    arc_offset += arc_delta;
   
    x = lerp(originX, destinationX, timer/jump_duration);
    y = lerp(originY, destinationY, timer/jump_duration) + arc_offset;
   
    if (timer >= jump_duration)
        state = "IDLE";
}
 

hippyman

Member
I tried using that, but the enemies keep jumping to 0,0 and not randomx, randomy. I don't know what I'm doing wrong here...

Code:
if (state == "JUMPING") {
    choose(move_towards_point(randomx, randomy, move_speed));
}

if timer >= 150 {
    state = choose("IDLE", "JUMPING", "JUMPING")
    timer = 0;
        }

if (state == "JUMPING") {
randomx = random_range(self.x-200, self.x+200);
randomy = random_range(self.y-200, self.y+200);
}
Change that to this and it might work.

Code:
if (state == "JUMPING") {
    randomx = random_range(self.x-200, self.x+200);
    randomy = random_range(self.y-200, self.y+200);
    choose(move_towards_point(randomx, randomy, move_speed));
}

if timer >= 150 {
    state = choose("IDLE", "JUMPING", "JUMPING")
    timer = 0;
        }
 
H

HenrikoNumberOne

Guest
Change that to this and it might work.

Code:
if (state == "JUMPING") {
    randomx = random_range(self.x-200, self.x+200);
    randomy = random_range(self.y-200, self.y+200);
    choose(move_towards_point(randomx, randomy, move_speed));
}

if timer >= 150 {
    state = choose("IDLE", "JUMPING", "JUMPING")
    timer = 0;
        }
Alright so this code kinda worked, but the enemies just kept wiggling back and forth in the air. Thanks anyway!

i try to keep the code as similar as your's
Code:
var jump_duration = 30;
var jump_radius = 200;
var max_idle_time = 30;

timer++;

if (timer >= jump_duration + cooldown) {
    timer = 0;
    arc_offset = 0;
    state = "JUMPING";
    cooldown = 1+irandom(max_idle_time);
 
    originX = x;
    originY = y;
 
    destinationX = random_range(self.x-jump_radius, self.x+jump_radius);
    destinationY = random_range(self.y-jump_radius, self.y+jump_radius);
    move_speed = point_distance(x,y,destinationX,destinationY);
}

if (state = "JUMPING") {
    var arc_delta = sign (timer - jump_duration/2);
    arc_offset += arc_delta;
 
    x = lerp(originX, destinationX, timer/jump_duration);
    y = lerp(originY, destinationY, timer/jump_duration) + arc_offset;
 
    if (timer >= jump_duration)
        state = "IDLE";
}
This code works flawlessly! Thank you so much! *fistbump*

Although... I also want the enemies to sometimes jump towards obj_player, and not randomly. This would mimic their true behavior completely! I think I can set up some kind of choose() system for that, right? I'm not really sure how to do that but I will try my best.

Edit: Urgh. My method didn't work that well. I tried using choose() to change the destinationX and destinationY coordinates randomly, but it just gave me a crash. Any better ways to do it?
 
Last edited by a moderator:

NicoFIDI

Member
:)

Code:
var jump_duration = 30;
var jump_radius = 200;
var max_idle_time = 30;

timer++;

if (timer >= jump_duration + cooldown) {
    timer = 0;
    arc_offset = 0;
    state = "JUMPING";
    cooldown = 1+irandom(max_idle_time);
   
    originX = x;
    originY = y;
   
    var jumpToPlayer = irandom(4) == 0;
    if (jumpToPlayer && instance_exists(obj_player)) {
        var playerDirection = point_direction(x,y,obj_player.x,obj_player.y);
        var intensity = min (point_distance(x,y,obj_player.x,obj_player.y), irandom(jump_radius));
       
        destinationX = dcos(playerDirection)*intensity;
        destinationX =-dsin(playerDirection)*intensity;
    } else {
        destinationX = random_range(self.x-jump_radius, self.x+jump_radius);
        destinationY = random_range(self.y-jump_radius, self.y+jump_radius);
    }
}

if (state = "JUMPING") {
    var arc_delta = sign (timer - jump_duration/2);
    arc_offset += arc_delta;
   
    x = lerp(originX, destinationX, timer/jump_duration);
    y = lerp(originY, destinationY, timer/jump_duration) + arc_offset;
   
    if (timer >= jump_duration)
        state = "IDLE";
}
 
H

HenrikoNumberOne

Guest
:)

Code:
var jump_duration = 30;
var jump_radius = 200;
var max_idle_time = 30;

timer++;

if (timer >= jump_duration + cooldown) {
    timer = 0;
    arc_offset = 0;
    state = "JUMPING";
    cooldown = 1+irandom(max_idle_time);
  
    originX = x;
    originY = y;
  
    var jumpToPlayer = irandom(4) == 0;
    if (jumpToPlayer && instance_exists(obj_player)) {
        var playerDirection = point_direction(x,y,obj_player.x,obj_player.y);
        var intensity = min (point_distance(x,y,obj_player.x,obj_player.y), irandom(jump_radius));
      
        destinationX = dcos(playerDirection)*intensity;
        destinationX =-dsin(playerDirection)*intensity;
    } else {
        destinationX = random_range(self.x-jump_radius, self.x+jump_radius);
        destinationY = random_range(self.y-jump_radius, self.y+jump_radius);
    }
}

if (state = "JUMPING") {
    var arc_delta = sign (timer - jump_duration/2);
    arc_offset += arc_delta;
  
    x = lerp(originX, destinationX, timer/jump_duration);
    y = lerp(originY, destinationY, timer/jump_duration) + arc_offset;
  
    if (timer >= jump_duration)
        state = "IDLE";
}
That works perfectly! Thank you!
 

samspade

Member
:)

Code:
var jump_duration = 30;
var jump_radius = 200;
var max_idle_time = 30;

timer++;

if (timer >= jump_duration + cooldown) {
    timer = 0;
    arc_offset = 0;
    state = "JUMPING";
    cooldown = 1+irandom(max_idle_time);
 
    originX = x;
    originY = y;
 
    var jumpToPlayer = irandom(4) == 0;
    if (jumpToPlayer && instance_exists(obj_player)) {
        var playerDirection = point_direction(x,y,obj_player.x,obj_player.y);
        var intensity = min (point_distance(x,y,obj_player.x,obj_player.y), irandom(jump_radius));
     
        destinationX = dcos(playerDirection)*intensity;
        destinationX =-dsin(playerDirection)*intensity;
    } else {
        destinationX = random_range(self.x-jump_radius, self.x+jump_radius);
        destinationY = random_range(self.y-jump_radius, self.y+jump_radius);
    }
}

if (state = "JUMPING") {
    var arc_delta = sign (timer - jump_duration/2);
    arc_offset += arc_delta;
 
    x = lerp(originX, destinationX, timer/jump_duration);
    y = lerp(originY, destinationY, timer/jump_duration) + arc_offset;
 
    if (timer >= jump_duration)
        state = "IDLE";
}
I'm not the original poster, but I'm also interested in this question. I understand all of your code except for the following part. What does this portion do:

Code:
        destinationX = dcos(playerDirection)*intensity;
        destinationX =-dsin(playerDirection)*intensity;
Or more accurately I know what it must accomplish, but I don't know how it does so. Also are they both supposed to be destinationX?

My solution to the problem would have been:

Code:
if (jumpToPlayer && instance_exists(obj_player)) {
    var playerDirection = point_direction(x,y,obj_player.x,obj_player.y);
    var current_jump_radius = irandom(jump_radius)
    var dist_to_player = point_distance(x,y,obj_player.x,obj_player.y);
    if (dist_to_player < current_jump_radius {
        destinationX = x + lengthdir_x(dist_to_player, playerDirection);
        destinationY = y + lengthdir_y(dist_to_player, playerDirection);
    } else {
        destinationX = x + lengthdir_x(current_jump_radius, playerDirection);
        destinationY = y + lengthdir_y(current_jump_radius, playerDirection);
    }
}
But your code is much simpler, so I'm curious how it works.

Edit: Never mind. I basically figured it out. I assume that it is supposed to be destinationY though. Basically sin and cos give you the ratio of x and y to the intensity which gives you the actual x and y distance when you multiply that ratio with the intensity.
 
Last edited:

NicoFIDI

Member
Yea, sorry about that, i didnt test the code, but It was suposed to be destinationY and add x in destinationX and y in destinationY as you say n.n
 

TheouAegis

Member
Maybe i will hack the tektites Friday if i feel like studying Zelda's code again. But i do like (at a glance) this ad libbed code.
 
Top