In my Gridworld program, I have a citizen that acts like a Bug, and a Criminal that turns the Citizen into a Victim. My Police actor, although not completely done, currently aids the victim. However, in a bounded grid, it does not recognize the next location is invalid. Here is my code.
public void act()
{
Grid<Actor> gr = getGrid();
Location loca = getLocation();
Location next = loca.getAdjacentLocation(getDirection());
Actor neighbor = gr.get(next);
if (gr.isValid(next))
{
ArrayList<Location> locs = getGrid().getOccupiedLocations();
for(Location loc: locs)
{
if (getGrid().get(loc) instanceof Victim)
{
Location prev = loc.getAdjacentLocation(getDirection()-180);
moveTo(prev);
}
else if( neighbor instanceof Victim || neighbor instanceof Citizen)
turn();
else
moveTo(next);
}
}
else
turn();
}
Try moving Actor neighbor = gr.get(next); after your if statement.
if (gr.isValid(next))
{
Actor neighbor = gr.get(next);
ArrayList<Location> locs = getGrid().getOccupiedLocations();
for(Location loc: locs)
...
That way your next location is checked to make sure it's in the grid before trying to get an Actor from there.
One other thing, in your second if statement you call getGrid().get(next), but you already have gr as the current grid, so you can just use gr.get(next). There's no reason to create a variable and not use it.
Related
My goal is to achieve that players on my bukkit server only hear each other, when there are no walls between them. So my idea was to get the distance between the sender of a message on the AsyncPlayerChatEvent and the recipient (getRecipients()) using a (Flying)Pathfinder(Goal), so that there is a path (throught the air) to the other player. If there is no way or the path is too long, I would remove the recipient from the list.
What I have so far:
#EventHandler
public void onAsyncPlayerChat(AsyncPlayerChatEvent e) {
Player p = e.getPlayer();
Location start = p.getLocation();
if (start.getWorld() == null) {
return;
}
PathfinderFlying pathfinder = new PathfinderFlying();
World world = ((CraftPlayer) p).getHandle().getWorld();
ChunkCache chunkCache = new ChunkCache(world,
new BlockPosition(start.getX() - 500, 0, start.getZ() - 500),
new BlockPosition(start.getX() + 500, 0, start.getZ() + 500)); //Dunno if this is correct
// EntityInsentientImplementation is basically: EntityInsentientImplementation extends EntityInsentient with default constructor
pathfinder.a(chunkCache, new EntityInsentientImplementation(EntityTypes.am, world));
for (Player target : e.getRecipients()) {
Location dest = target.getLocation();
// How do I get the distance?
}
}
I already thried the function public int a(PathPoint[] var0, PathPoint var1) { from PathfinderFlying but this seems to return a static value (26) when var0 is
the location of th sender and var1 is the location of the recipient.
I'm using bukkit 1.17.1.
I was working on how to find the best way to go at specific location. So, I made BaritoneCalculator.
You should do like that to use it :
GoalBlock goal = new GoalBlock(x, y, z); // create direction goal
BaritoneAPI.getProvider().getNewBaritone(p).getPathingBehavior().startGoal(goal);
Now, it will calculate the better path.
To get the path, use this :
BaritoneAPI.getProvider().getBaritone(p).getPathingBehavior().getPath();
Or, you can also use an event: PathCalculatedEvent.
Full code to count all positions to pass through (i.e. your issue) :
PathingBehavior pathing = BaritoneAPI.getProvider().getNewBaritone(p).getPathingBehavior();
GoalBlock goal = new GoalBlock(x, y, z); // create direction goal
pathing.startGoal(goal); // start goal and calculate
Optional<IPath> optPath = pathing.getPath();
if(optPath.isPresent()) { // can be not found yet, use event to be sure
int distance = pathing.get().positions().size() -1; // -1 to don't count current player position
// now you have the distance
} else {
// failed to find way
}
More informations (and updated) on readme.
Okay so I'm making a photography game where when you 'take a photo', Unity sends a few raycasts forward to check if certain tagged items are in the photo (all within the cameras FOV). My problem is, this seems to work intermittently! Sometimes it finds the tagged objects, other times it will be right in front of the view yet it will miss it completely! Can anyone advise about what I'm doing wrong?
public static Transform target;
public static GameObject[] targetName;
public static float length = 250f;
public static Transform thisObject;
// Start is called before the first frame update
void Start()
{
thisObject = GameObject.Find("Main Camera").GetComponent<Transform>();
//target = GameObject.FindGameObjectWithTag("Trees").transform;
}
// Update is called once per frame
void Update()
{
//InFront();
//HasLineOfSight("Trees");
}
public static bool InFront(Transform target1)
{
Vector3 directionToTarget = thisObject.position - target1.position;
float angleOnXAxis = Vector3.Angle(thisObject.right, directionToTarget);
float angleOnYAxis = Vector3.Angle(thisObject.up, directionToTarget);
//Debug.Log(angleOnYAxis);
if (Mathf.Abs(angleOnXAxis) < 130 && Mathf.Abs(angleOnXAxis) > 50
&& Mathf.Abs(angleOnYAxis) < 115 && Mathf.Abs(angleOnYAxis) > 62)
{
//Debug.DrawLine(transform.position, target.position, Color.green);
return true;
}
return false;
}
public static bool HasLineOfSight(string objectTag)
{
RaycastHit hit;
Vector3 direction = target.position - thisObject.position;
//Debug.Log(direction);
if (Physics.Raycast(thisObject.position, direction, out hit, length))
{
if (hit.transform.tag == objectTag)
{
Debug.DrawRay(thisObject.position, direction * 0.96f, Color.red);
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
public static GameObject SortObjects(string objectTag)
{
targetName = GameObject.FindGameObjectsWithTag(objectTag);
GameObject closestObject = null;
for (int i = 0; i < targetName.Length; i++)
{
if (Vector3.Distance(thisObject.position,
targetName[i].transform.position) <= length)
{
if (InFront(targetName[i].transform))
{
if (closestObject == null)
{
closestObject = targetName[i];
}
else
{
if (Vector3.Distance(targetName[i].transform.position, thisObject.position) <= Vector3.Distance(closestObject.transform.position, thisObject.position))
{
closestObject = targetName[i];
}
}
}
}
}
return closestObject;
}
public static bool ObjectCheck(string objectTag)
{
//Debug.Log(SortObjects(objectTag));
if (SortObjects(objectTag) != null)
{
target = SortObjects(objectTag).transform;
//Debug.Log(target);
if (InFront(target) && HasLineOfSight(objectTag))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
I'm essentially calling ObjectCheck() with the tag I want to check for to get the closest, visible, object with that tag. What is wrong with this code??
In your script, only the closest object to the main camera gets checked. SortObjects() determines the closest tagged object, and then you only handle that single object in ObjectCheck(). - That object might be obstructed by something else, so the method returns false. And other tagged objects that are actually visible, are not picked up this way...
So, you could rename and change your SortObjects() function to check for both conditions right in the loop (InFront(target) && HasLineOfSight(objectTag)), and filter the objects out right in there, since only those objects are of interest.
Also, your HasLineOfSight() method checks the tag of the hit object, but what you probably wanted to do, is to check if the raycast actually hits that exact object. So it should instead compare the hit's gameObject to the target's gameObject, ignoring the tag, since a correct tag alone isn't enough. (Side note: it would make sense to place all "photographable objects" on a "photo layer", and set the layer mask in the Physics.Raycast() call accordingly, it's more efficient that way in larger scenes.)
The way the angles are calculated in the InFront() method is probably causing issues, because the direction vector to the target is really in 3D. To calculate the angles, you could try to use Vector3.Project() or Vector3.ProjectOnPlane(), but that will also be problematic, because of perspective camera issues.
This check is strongly related to the topic of "frustum culling", a technique usually used for rendering. But it's similar to what you need, to filter out all the (possibly) visible objects in the camera's field of view (frustum culling doesn't handle obstruction, it is just a geometric check to see if a point lies within the camera's frustum space). See:
https://en.wikipedia.org/wiki/Viewing_frustum
https://en.wikipedia.org/wiki/Hidden-surface_determination#Viewing-
http://www.lighthouse3d.com/tutorials/view-frustum-culling/
https://docs.unity3d.com/Manual/UnderstandingFrustum.html
If you want to dig deeper and optimize this, there are a couple of ways this can be done. But luckily, Unity comes with many useful related functions already built into the Camera class. So instead, you could use Camera.WorldToScreenPoint() (or Camera.WorldToViewportPoint()), and compare the resulting screen coordinates to the screen size or viewport, like discussed in Unity forum. (The frustum math is hidden behind these compact functions, but beware that this is probably not the optimal way to do this.)
Instead of calling FindGameObjectsWithTag() every time, you could do it only once in Start(), assuming objects do not get created/destroyed while the game is running.
I've tried to modify your script, since I'm also learning Unity again... The script can be dragged to the main camera, and it should show the "focus object" in the Scene view with the green debug line. I hope this helps:
using UnityEngine;
[RequireComponent(typeof(Camera))]
public class PhotoCast : MonoBehaviour
{
public float maxDistance = 250.0f;
public string objectTag = "photo";
protected GameObject[] objs;
protected GameObject objFocus;
protected Camera cam;
public void Start() {
objs = GameObject.FindGameObjectsWithTag(objectTag);
cam = GetComponent<Camera>();
}
public void Update() {
if (Input.GetButtonDown("Fire1")) {
objFocus = CheckObjects();
if (objFocus) {
Debug.Log("closest object in view: " + objFocus.name);
/* TODO: take actual photo here */
}
}
if (objFocus) {
Debug.DrawLine(transform.position,
objFocus.transform.position, Color.green);
}
}
GameObject CheckObjects() {
GameObject obj_closest = null;
float dist_closest = float.MaxValue;
foreach (GameObject o in objs) {
float dist = Vector3.Distance(
o.transform.position, transform.position);
if (dist < maxDistance && dist < dist_closest
&& InViewport(o.transform.position)
&& HasLineOfSight(o.transform)) {
dist_closest = dist;
obj_closest = o;
}
}
return obj_closest;
}
bool InViewport(Vector3 worldPos) {
Vector3 p = cam.WorldToViewportPoint(worldPos);
return (p.x > 0.0f && p.x <= 1.0f && p.y > 0.0f && p.y <= 1.0f
&& p.z > cam.nearClipPlane);
}
bool HasLineOfSight(Transform target) {
RaycastHit hit;
Vector3 dir = target.position - transform.position;
if (Physics.Raycast(transform.position, dir, out hit, maxDistance)) {
if (hit.collider.gameObject == target.gameObject) {
return true;
}
}
return false;
}
}
Side notes:
Another issue with this technique is, that there can be tagged objects right in front of the camera, but other tagged objects that are closer on the side will be picked up instead of the obvious one. Many small issues to fine-tune until the scripts fits the game, I guess. Instead of only using one Raycast per object, you could use multiple ones, and take the bounding box or the actual collider shape into account.
An improved version of the script could make use of the Physics.Overlap*() or Physics.*Cast*() functions, documented here.
the code below is for a fundraiser dinner to purchase a land, the purpose is to show the progress of the square meter of land purchased (around 2976m2). everytime a square meter is purchased, the application adds an image tile which corresponds to an acctual 1m2. eventually the tiles (~2976 of them) fill up like in a grid to complete the land once fully purchased.
The size of each tiles is around 320bytes, there are 2976 tiles in total.
I have also showing below an image example.
The thing that drives me crazy with this code (in javafx) is that it consumes around 90 to 100% of 1 of my processors and the memory usage keeps increasing as the tiles add up until the code buffer run out of memory and the program crashes after a while. this is not desirable during the fundraising dinner.
the full code is available for testing at
you will need to change boolean split to true false, which will split the images for you, (around 3000 images);
https://github.com/rihani/Condel-Park-Fundraiser/tree/master/src/javafxapplication3
The main culprit that uses all the memory and CPU is the AnimationTimer() function shown below and I am wondering if anyone can help me reduce memory and CPU usage in this code.
to briefly explain how the code below is used, the land is divided into 2 panes, when the first one grid_pane1 is filled up the second pane grid_pane2 starts to then fill up.
also a flashing tile is used to show the current progress.
I am using total_donnation ++; to test the code, but would normally use mysql to pull the new value raised during the findraising dinner
AnimationTimer() Code:
translate_timer = new AnimationTimer() {
#Override public void handle(long now) {
if (now > translate_lastTimerCall + 10000_000_000l)
{
old_total_donnation = total_donnation;
try
{
// c = DBConnect.connect();
// SQL = "Select * from donations";
// rs = c.createStatement().executeQuery(SQL);
// while (rs.next())
// {total_donnation = rs.getInt("total_donnation");}
// c.close();
total_donnation ++;
if(total_donnation != old_total_donnation)
{
System.out.format("Total Donation: %s \n", total_donnation);
old_total_donnation = total_donnation;
if (!pane1_full)
{
grid_pane1.getChildren().clear();
grid_pane1.getChildren().removeAll(imageview_tile1,hBox_outter_last);
}
grid_pane2.getChildren().clear();
grid_pane2.getChildren().removeAll(imageview_tile2,hBox_outter_last);
for(i=0; i<=total_donnation; i++)
{
if (pane1_full){ System.out.println("Pane 1 has not been redrawn"); break;}
file1 = new File("pane1_img"+i+".png");
pane1_tiled_image = new Image(file1.toURI().toString(),image_Width,image_Height,false,false);
imageview_tile1 = new ImageView(pane1_tiled_image);
grid_pane1.add(imageview_tile1, current_column_pane1,current_row_pane1);
current_column_pane1 = current_column_pane1+1;
if (current_column_pane1 == max_columns_pane1 )
{
current_row_pane1 = current_row_pane1+1;
current_column_pane1 = 0;
}
if (i == max_donnation_pane1 ){ pane1_full = true; System.out.println("Pane 1 full"); break;}
if (i == total_donnation)
{
if (i != max_donnation_pane1)
{
hBox_outter_last = new HBox();
hBox_outter_last.setStyle(style_outter);
hBox_outter_last.getChildren().add(blink_image);
ft1 = new FadeTransition(Duration.millis(500), hBox_outter_last);
ft1.setFromValue(1.0);
ft1.setToValue(0.3);
ft1.setCycleCount(Animation.INDEFINITE);
ft1.setAutoReverse(true);
ft1.play();
grid_pane1.add(hBox_outter_last, current_column_pane1,current_row_pane1);
}
}
}
if (i < total_donnation)
{
total_donnation_left = total_donnation - max_donnation_pane1;
for(j=0; j<=total_donnation_left; j++)
{
file2 = new File("pane2_img"+j+".png");
pane2_tiled_image = new Image(file2.toURI().toString(),image_Width,image_Height,false,false);
imageview_tile2 = new ImageView(pane2_tiled_image);
grid_pane2.add(imageview_tile2, current_column_pane2,current_row_pane2);
current_column_pane2 = current_column_pane2+1;
if (current_column_pane2 == max_columns_pane2 )
{
current_row_pane2 = current_row_pane2+1;
current_column_pane2 = 0;
}
if (j == max_donnation_pane2 ){ System.out.println("Pane 2 full"); break;}
if (j == total_donnation_left)
{
if (j != max_donnation_pane2)
{
hBox_outter_last = new HBox();
hBox_outter_last.setStyle(style_outter);
hBox_outter_last.getChildren().add(blink_image);
ft = new FadeTransition(Duration.millis(500), hBox_outter_last);
ft.setFromValue(1.0);
ft.setToValue(0.3);
ft.setCycleCount(Animation.INDEFINITE);
ft.setAutoReverse(true);
ft.play();
grid_pane2.add(hBox_outter_last, current_column_pane2,current_row_pane2);
}
}
}
}
current_column_pane1 =0;
current_row_pane1=0;
current_column_pane2=0;
current_row_pane2=0;
}
}
catch (Exception ex) {}
translate_lastTimerCall = now;
}
}
};
First and foremost, you create a lot of indefinite FadeTransitions that are never stopped. These add up over time and cause both memory and CPU leaks. You should stop() the transition before starting a new one. Alternatively, you only need one transition to interpolate the value of a DoubleProperty and then bind node's opacity to this property:
DoubleProperty opacity = new SimpleDoubleProperty();
Transition opacityTransition = new Transition() {
protected void interpolate(double frac) {
opacity.set(frac);
}
};
// elsewhere
hBox_outter_last.opacityProperty().bind(opacity);
You may want to preload all the image tiles beforehand, so that you avoid reading from disk in the loop.
You unnecessarily destroy and recreate large part of the scene in every cycle. You should modify your code to only add the new tiles and not drop them all and recreate them from scratch.
Finally, when you actually query the database, you should do it from a different thread and not the JavaFX application thread, because your UI will be unresponsive for the time of the query (e.g. not animating your fade transitions).
I have a suggestion:
Do not split the image instead using 2 panels. One for displaying the whole image. The second will be a grid pane overlapping the first pane. Therefore, when a square meter is purchased, the background of corresponding grid-cell will become transparent.
I am new to XNA and CSharp programming so I want to learn to make a treasure hunting game as a beginning so I made a player(as a class) which can walk up, down, left and right. I made a Gem class also which the player can collide with and the gem disappears and a sound is played. But I want to make some walls that the player can collide with and stop so I made a class called Tile.cs (The wall class) and I made a void in it
public void CollideCheck(bool tWalk, bool bottomWalk, bool leftWalk, bool rightWalk, Rectangle topRect, Rectangle bottomRect, Rectangle rightRect, Rectangle leftRect)
{
colRect = new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height);
if (this.colRect.Intersects(topRect))
{
tWalk = false;
}
else
tWalk = true;
if (this.colRect.Intersects(bottomRect))
{
bottomWalk = false;
}
else
bottomWalk = true;
if (this.colRect.Intersects(leftRect))
{
leftWalk = false;
}
else
leftWalk = true;
if (this.colRect.Intersects(rightRect))
{
rightWalk = false;
}
else
rightWalk = true;
}
Then, in the Game1.cs (The main Class) I made an array of "Tiles":
Tile[] tiles = new Tile[5];
And in the update void I made this:
foreach (Tile tile in tiles)
{
tile.CollideCheck(player.topWalk, player.bottomWalk, player.leftWalk, player.rightWalk,
new Rectangle((int)player.Position.X, (int)player.Position.Y - (int)player.Speed.Y, player.currentAnim.FrameWidth, player.currentAnim.FrameHeight),
new Rectangle((int)player.Position.X, (int)player.Position.Y + (int)player.Speed.Y, player.currentAnim.FrameWidth, player.currentAnim.FrameHeight),
new Rectangle((int)player.Position.X + (int)player.Speed.X, (int)player.Position.Y, player.currentAnim.FrameWidth, player.currentAnim.FrameHeight),
new Rectangle((int)player.Position.X - (int)player.Speed.X, (int)player.Position.Y, player.currentAnim.FrameWidth, player.currentAnim.FrameHeight));
}
All those rectangles are the borders of the player but when I run the game the player doesn't collide with it so is there any way to fix this?
I can post the project if I am not very clear.
Your parameters are in only, but you set their values inside the call. You have to declare them as out variables so that their value is sent back to the caller. Using out also makes sure you always set a value to them before exiting the function.
So change your function declaration to public void CollideCheck(out bool tWalk, out bool bottomWalk, out bool leftWalk, out bool rightWalk, Rectangle topRect, Rectangle bottomRect, Rectangle rightRect, Rectangle leftRect) and you get the values back.
The code I am using for controlling the four-directional movement of the player's sprite in my 2D game is exhibiting some unwanted affection. I realize that this affection is because the if conditions that are first met will trump the later else ifs... So the directional affection my code shows now is: left > right > up > down.
What kind of affection I want is: the first direction pressed > the second direction pressed > the third direction pressed > the fourth direction pressed.
I also want it to remember what order the keypresses are in untill they're released.
Example:
I hold left, the sprite moves left.
I push up while still holding left, and the sprite immediately moves up.
I release up while still holding left, and the sprite resumes its movement left.
This memory should encompass all four directional keys so that the controls won't feel buggy if the user has "fat fingers".
This is the code I use for movement so far:
if (CurrentKeyboardState.IsKeyDown(Keys.Left) == true)
{
Speed.X = moveSpeed;
Direction.X = moveLeft;
}
else if (CurrentKeyboardState.IsKeyDown(Keys.Right) == true)
{
Speed.X = moveSpeed;
Direction.X = moveRight;
}
else if (CurrentKeyboardState.IsKeyDown(Keys.Up) == true)
{
Speed.Y = moveSpeed;
Direction.Y = moveUp;
}
else if (CurrentKeyboardState.IsKeyDown(Keys.Down) == true)
{
Speed.Y = moveSpeed;
Direction.Y = moveDown;
}
I am thinking I could use a List and just put the direction pressed (left, right, up, down) as strings into the list if it isn't already in the list, and then always check what the latest item in the list is to decide what directio to move. And of course remove the strings when the corresponding keys are released. Would this be a good way of solving it?
Here is my attempt on this:
if (currentKeyboardState.IsKeyDown(Keys.Left))
{
if (!keyDownList.Contains("left"))
{
keyDownList.Add("left");
System.Diagnostics.Debug.WriteLine("left inserted");
}
}
else if (oldKeyboardState.IsKeyDown(Keys.Left))
{
keyDownList.Remove("left");
System.Diagnostics.Debug.WriteLine("left removed");
}
if (currentKeyboardState.IsKeyDown(Keys.Right))
{
if (!keyDownList.Contains("right"))
{
keyDownList.Add("right");
System.Diagnostics.Debug.WriteLine("right added");
}
}
else if (oldKeyboardState.IsKeyDown(Keys.Right))
{
keyDownList.Remove("right");
System.Diagnostics.Debug.WriteLine("right removed");
}
if (currentKeyboardState.IsKeyDown(Keys.Up))
{
if (!keyDownList.Contains("up"))
{
keyDownList.Add("up");
System.Diagnostics.Debug.WriteLine("up added");
}
}
else if (oldKeyboardState.IsKeyDown(Keys.Up))
{
keyDownList.Remove("up");
System.Diagnostics.Debug.WriteLine("up removed");
}
if (currentKeyboardState.IsKeyDown(Keys.Down))
{
if (!keyDownList.Contains("down"))
{
keyDownList.Add("down");
System.Diagnostics.Debug.WriteLine("down added");
}
}
else if (oldKeyboardState.IsKeyDown(Keys.Down))
{
keyDownList.Remove("down");
System.Diagnostics.Debug.WriteLine("down removed");
}
try
{
if (keyDownList[keyDownList.Count-1].Contains("left"))
{
//move left
speed.X = moveSpeed;
direction.X = moveLeft;
}
else if (keyDownList[keyDownList.Count-1].Contains("right"))
{
//move right
speed.X = moveSpeed;
direction.X = moveRight;
}
else if (keyDownList[keyDownList.Count-1].Contains("up"))
{
//move up
speed.Y = moveSpeed;
direction.Y = moveUp;
}
else if (keyDownList[keyDownList.Count-1].Contains("down"))
{
//move down
speed.Y = moveSpeed;
direction.Y = moveDown;
}
}
catch (Exception e)
{
}
I had some problems with it initially, but it seems to work fine now with the exception of it generating exceptions (A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll) while my sprite is standing still. Any tips on how to stop that?
I'm not just looking for a solution that works, but for something durable and efficient that feels rock solid and professional, so discussion on the topic is more than welcome.
Durable, efficient, rock solid, etc. it may not be, but what you're saying with your if/else if block there is that you're only interested in one keystate per frame, when I don't think that's the case.
What happens if you try:
if (CurrentKeyboardState.IsKeyDown(Keys.Down) & !CurrentKeyboardState.IsKeyDown(Keys.Up))
{
Speed.Y = moveSpeed;
Direction.Y = moveDown;
}
if (CurrentKeyboardState.IsKeyDown(Keys.Up) & !CurrentKeyboardState.IsKeyDown(Keys.Down))
{
Speed.Y = moveSpeed;
Direction.Y = moveUp;
}
And repeat similar for left and right. By testing mutual exclusivity between opposing directions, you keep yourself from adding to and subtracting from direction in the same frame. Also, by using separate conditions instead of an if/elseif chain, you allow the possibility to process Left + Up in the same frame.