This site requires JavaScript, please enable it in your browser!
Greenfoot back
LewisEro
LewisEro wrote ...

2020/3/25

Making an NPC randomly roam an area WITHOUT rotating the image

1
2
LewisEro LewisEro

2020/3/25

#
i think i managed to implement your approach, with addedToWorld now. not sure if this is how you intended
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class NPC here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class FloatingSkull extends Actor
{
    PC player;
    private int rotation = Greenfoot.getRandomNumber(360);
    private int speed = 1;
    private boolean aggro = false;
    private int[] roamLimit = new int[4];
    private int roamLimitRange = 50;
    
    public void act(){
        movementAI();//track the player as soon as they enter a certain AOE, increase speed
    }
    protected void addedToWorld(MyWorld World){
            roamLimit[0] = getX()+roamLimitRange;
            roamLimit[1] = getX()-roamLimitRange;
            roamLimit[2] = getY()+roamLimitRange;
            roamLimit[3] = getY()-roamLimitRange; 
    }
    public FloatingSkull(PC player){
        this.player = player;
    }  
    public void movementAI(){
            if(getObjectsInRange(200, PC.class).isEmpty() && aggro == false){
                rotation  += 15-Greenfoot.getRandomNumber(31); //  (-15, 15) degree change in direction
                setRotation(rotation);
                move(speed*2);
                setRotation(0);
                if(getX() < roamLimit[0] || getX() > roamLimit[1] || getY() < roamLimit[2] || getY() > roamLimit[3]){
                    move(speed*(-1));
                }
            }
            if(!getObjectsInRange(150, PC.class).isEmpty()){
                move(speed*0);
            }
            else{
                turnTowards(player.getX(), player.getY());         
                move(speed);
                setRotation(0);
            }
            if(!getObjectsInRange(200, PC.class).isEmpty()){
                aggro = true;
            }
    }
}
so sorry for all the posts, i just really want this to work
danpost danpost

2020/3/26

#
LewisEro wrote...
the issue there i believe was that i did not properly declare my array globally (line 15) << Code Omitted >> this runs without the error, but does not achieve the effect. if you're still interested in the error it is this: << Error Trace Omitted >>
That was indeed correct that the array was not created to put values into it yet. Good job on finding that. Try this:
import greenfoot.*;

public class FloatingSkull extends Actor
{
    private PC player;
    private int[] roamLimit = new int[4];
    private int rotation = Greenfoot.getRandomNuber(360);
    private int roamLimitRange = 50;
    
    public FloatingSkull(PC player) {
        this.player = player;
    }
    
    protected void addedToWorld(World world) {
        roamLimit[0] = getX()+roamLimitRange;
        roamLimit[1] = getX()-roamLimitRange;
        roamLimit[2] = getY()+roamLimitRange;
        roamLimit[3] = getY()-roamLimitRange;
    }
    
    public void act() {
        movementAI();
    }
    
    private void movementAI() {
        rotation += 15-Greenfoot.getRandomNumber(31);
        move(2);
        if ( ! getObjectsInRange(150, PC.class).isEmpty() ) move(-2);
        else if (getObjectsInRange(200, PC.class).isEmpty()) move(-1);
        else {
            turnTowards(player.getX(), player.getY());
            rotation = getRotation();
        }
        setRotation(0);
        boolean limitReached = false;
        if (getX() > roamLimit[0]) { setLocation(roamLimit[0], getY()); limitReached = true; }
        if (getX() < roamLimit[1]) { setLocation(roamLimit[1], getY()); limitReached = true; }
        if (getY() > roamLimit[2]) { setLocation(getX(), roamLimit[2]); limitReached = true; }
        if (getY() < roamLimit[3]) { setLocation(getX(), roamLimit[3]); limitReached = true; }
        if (limitReached) rotation += 150+Greenfoot.getRandomNumber(61);
    }
}
LewisEro LewisEro

2020/3/26

#
Thanks a lot for the effort! So this causes the skeleton to move east in a straight line roughly 50 units and come to a standstill. Thereafter it idles no matter what, even if you come into the range where it should track the player. I could upload some footage to YouTube if you think it may help?
danpost danpost

2020/3/26

#
LewisEro wrote...
I could upload some footage to YouTube if you think it may help?
Not necessary. I can test it out myself.
danpost danpost

2020/3/26

#
danpost wrote...
I can test it out myself.
Okay. Add as 2nd line in movementAI (insert before the move line):
setRotation(rotation);
(sorry)
LewisEro LewisEro

2020/3/26

#
danpost wrote...
(sorry)
No problem. So, the skull definitely is confined to a square now! That's good. However, upon entering the tracking range, the skull tries to pursue the player but never actually is able to leave his confinement. Furthermore, the sprite is now rotating again (the thing we fixed on page 1). Also, the aggro == false boolean I had in my code served the purpose of maintaining the tracking on the player over any range, once it has been activated. I think the solution is very close.
danpost danpost

2020/3/26

#
LewisEro wrote...
the sprite is now rotating again (the thing we fixed on page 1).
Line 34 should be taking care of that.
upon entering the tracking range, the skull tries to pursue the player but never actually is able to leave his confinement. I did not realize that was something you wanted.
the aggro == false boolean I had in my code served the purpose of maintaining the tracking on the player over any range, once it has been activated. I think the solution is very close.
I see. Well,, you can make full use of your player field for both the confinement issue and the player tracking issue with:
import greenfoot.*;
 
public class FloatingSkull extends Actor
{
    private PC player;
    private int[] roamLimit = new int[4];
    private int rotation = Greenfoot.getRandomNuber(360);
    private int roamLimitRange = 50;
     
    public FloatingSkull() {
    }
     
    protected void addedToWorld(World world) {
        roamLimit[0] = getX()+roamLimitRange;
        roamLimit[1] = getX()-roamLimitRange;
        roamLimit[2] = getY()+roamLimitRange;
        roamLimit[3] = getY()-roamLimitRange;
    }
     
    public void act() {
        movementAI();
    }
     
    private void movementAI() {
        if (player != null)
        {
            turrnTowards(player.getX(), player.getY());
            if (getObjectsInRange(150, PC.class).isEmpty()) move(2);
        }
        else {
            rotation += 15-Greenfoot.getRandomNumber(31);
            setRotation(rotation);
            move(1);
            if ( ! getObjectsInRange(200, PC.class).isEmpty()) {
                player = (PC)getObjectsInRange(200, PC.class).get(0);
            }
            else {
                boolean limitReached = false;
                if (getX() > roamLimit[0]) { setLocation(roamLimit[0], getY()); limitReached = true; }
                if (getX() < roamLimit[1]) { setLocation(roamLimit[1], getY()); limitReached = true; }
                if (getY() > roamLimit[2]) { setLocation(getX(), roamLimit[2]); limitReached = true; }
                if (getY() < roamLimit[3]) { setLocation(getX(), roamLimit[3]); limitReached = true; }
                if (limitReached) rotation += 150+Greenfoot.getRandomNumber(61);
            }
        }
        setRotation(0);
    }
}
LewisEro LewisEro

2020/3/26

#
danpost wrote...
I did not realize that was something you wanted.
I'm sorry, I should have been more clear After readjusting a few lines here and there to make it compatible with my current code, this works absolutely perfectly. Thank you so much! I will go over this to try to fully understand it. Exactly how the confinement was achieved here is not so clear to me at this point..
danpost danpost

2020/3/26

#
Maybe this will help: Lines 25 - 30: If chasing player, chase to within 150 of it; otherwise (not chasing) lines 30 - 33: random patrol; lines 34 - 37: if spotting player, begin chase; otherwise (not spotted) lines 38 - 43: maintain confinement.
LewisEro LewisEro

2020/3/26

#
OK, that helps, but I have a few questions. line 7: as the code stands, is it still necessary to set the random number range to 360 here or is it sufficient to simply declare the integer as
private int rotation;
line 25, 35: not quite sure exactly what is happening in these lines. it looks like the player object is being handled as a boolean? lines 38 - 43: the way you are achieving confinement is by resetting the skull's location to the roamLimit and changing its rotation in 43? also in 43: why did you choose specifically 150+Greenfoot.getRandomNumber(61) as your values? thanks again.
danpost danpost

2020/3/26

#
LewisEro wrote...
line 7: as the code stands, is it still necessary to set the random number range to 360 here
Not necessary; however, without it, the actors will always initially move toward the right.
line 25, 35: not quite sure exactly what is happening in these lines. it looks like the player object is being handled as a boolean?
The PC field named player is being used. If it has not been assigned an object, then the chase has not begun. It is assign a PC object once it gets in range of the actor (see lines 34 and 35).
lines 38 - 43: the way you are achieving confinement is by resetting the skull's location to the roamLimit and changing its rotation in 43? also in 43: why did you choose specifically 150+Greenfoot.getRandomNumber(61) as your values?
Yes -- the confinement algorithm basically has the actor placed at the limit if passing the limit. The boolean is used to indicates if any limit was crossed and, if so, has the actor reverse direction (turns around 180 degrees -- plus or minus 30 degrees; so, between a 150 and a 210 degree turn).
LewisEro LewisEro

2020/3/26

#
aaah now it is clear. thank you dan! you're the man!!
You need to login to post a reply.
1
2