I am trying to take a position (a,b) and via the code receive a random new position (a,b).. I am having great trouble implementing the code and what I got is by far my best try..
type Teleport (a,b) =
inherit Item (a, b, ' ', Color.White, Color.White)
override this.FullyOccupy() = true
override this.InteractWith (p: Player) =
let mutable posX = p.X
let mutable posY = p.Y
let rand = System.Random()
posX <- rand.Next()
posY <- rand.Next()
Can someone maybe explain why it is not working?
It is supposed to work as a teleporter in a game, where if the player moves to the first (a,b) should be transported to a new (random) (a,b) position.
Thanks!
The reason your code doesn't work is that it never mutates the Player's position; InteractWith just copies the position into two local variables, and updates those.
This said, I strongly encourage you not to program in the OO-style if you want to learn F# - you'll be much happier going for a functional style.
One of the hallmarks of functional programming (FP) is immutability. For your teleport-thingy, this means NOT to mutate the Player's position, but to create a new player with the new position.
Try something along the following line
type Player = { X: int; Y: int; Name: string }
let teleport player =
let rand = System.Random()
{ player with X = rand.Next 100
Y = rand.Next 100 }
Also, try not to reach for a class as the solution for every problem, reach for a function instead; in the above, teleport is just a function Player -> Player.
I truly hope you'll enjoy F#; it's a great language for doing FP on .NET.
Related
hey guys , So as you can see i made a robot arm grab a slingshot's objectholder with a ball in it. My arm pulls it any direction I want it but I wanted the user to know which box is going to be shot at.
If you're applying an impulse force (or velocity) to your ball and there is gravity in your world, your item will follow the Projectile motion;
Here you can find details about it:
https://en.wikipedia.org/wiki/Projectile_motion
There are basically two main options
calculating it yourself
This is probably way better for performance especially if you want a really simple trajectory preview without accounting for any collision etc
refer to linked article. But it basically comes down to
and would need slightly rework from 2D to 3D physics, should be trivial though since the important part about the Y axis basically stays the same.
You would
Call this simulation with according supposed shoot direction and velocity
Visualize the tracked positions e.g. in a LineRenderer
Physics.Simulate
This allows you to run physics updates manually all within a single frame and actually let the Physics engine handle it all for you
This costs of course a lot of performance but you get all collisions etc accounted for automatically without getting a headache
You would
Make a snapshot of all Rigid bodies in your scene - in order to reset after the simulation
Simulate the desired amount of physics steps (XY seconds ahead) while keeping track of the simulated data
reset everything to the state tracked in step 1
use the simulated data from step 2 to visualize e.g. with a LineRenderer
This might look somewhat like e.g.
public class Prediction : MonoBehaviour
{
public LineRenderer line;
public Rigidbody tracked;
private Rigidbody[] allRigidbodies;
private void Awake()
{
allRigidbodies = FindObjectsOfType<Rigidbody>();
}
private void LateUpdate()
{
// Wherever you would get this from
Vector3 wouldApplyForce;
// Step 1 - snapshot
// For simplicity reasons for now just the positions
// using some Linq magic
var originalPositions = allRigidbodies.ToDictionary(item => item, item => item.position);
// Step 2 - Simulate e.g. 2 seconds ahead
var trackedPositions = new Vector3 [(int) (2 / Time.fixedDeltaTime)];
Physics.autoSimulation = false;
tracked.AddForce(wouldApplyForce);
for(var i = 0; i < trackedPositions.Length; i++)
{
Physics.Simulate(Time.fixedDeltaTime);
trackedPositions[i] = tracked.position;
}
// Step 3 - reset
foreach (var kvp in originalPositions)
{
kvp.Key.position = kvp.Value;
}
Physics.autoSimulate = true;
// Step 4 - Visualize
line.positionCount = trackedPositions.Length;
line.SetPositions(trackedPositions);
}
}
Of course we won't talk about performance here ^^
I've been trying to get a script working to check if my player is below a certain Y lvl, for a platformer. so it can be respawned to the beginning, But how do I put the y lvl inside a variable to check it? i cant figure it out lol
In the Update() run something like:
if(player.transform.position.y < 1)
{
//do something
}
where 'player' is the GameObject in question.
I am assuming you want to just want to compare (==, <=, >=, all that jazz is what I mean by comparing just in case you were not aware) the Y value to something like 10 for example. This is easy and you don't even need a variable necessarily for this.
//For the object position relative to the world
if(transform.position.y == 10) //"transform" gives you acces to the transform component
{ //of the object the script is attached to
Debug.Log("MILK GANG");
}
//For the object position relative to its Parent Object
if(transform.localPosition.y == 10)
{
Debug.Log("MILK GANG");
}
If you want to change the value of the position of your object then
transform.position = new Vector2(6, 9)//Nice
//BTW new Vector2 can be used if you dont
//want to assign a completely new variable
However, if you want to get a reference (Basically a variable that tells the code your talking about this component) to it.
private Transform Trans;
void Awake() //Awake is called/being executed before the first frame so its
{ //better than void Start in this case
Trans = GetComponent<Transform>();
Trans.position = new Vector2(69, 420); //Nice
}
This is the code way of doing it but there's another way that uses Unity
[SerializeField] private Transform Trans;
//[SerializeField] makes the variable changeable in Unity even if it is private so you
//can just drag and drop on to this and you good to go
Hope this help
if it doesn't
then welp I tried lel
You can use a script added to gameobject to check transform.position of the object.
if(transform.position.y < ylvl)
{
//do something
}
where ylvl is the integer of the height you want to check
I'm trying to come up with a calculated way to compare current speed vs distance to the next waypoint, with the end goal that the computer car makes a decision to "coast," brake, or keep the throttle on in the best way while turning the best way possible so that it doesn't OVERSHOOT the waypoint (like the Standard Unity assets car currently does when using the waypoint AI). I feel like there's a few things I'm failing to grasp, however. I've had to set up a TON of barriers and something I call "PowerZones" (zones that control the amount of brake and engine torque on the car in terms of percentages). Here's my current course below, which is of course incomplete in waypoints, but the point is to note how many of these zones and obstacles there is. I really don't feel there should HAVE to be this many!
However, the reason that I have SO many is because it's been kinda difficult for me to come up with an ideal function to optimize these kinds of driving and steering decisions as the opponent. Here's the Drive and Steer functions for the vehicle (some of which are based on an existing Eyemaginary tutorial):
private void Drive()
{
float currDistFromWP = Vector3.Distance(transform.position, nodes[currentNode].position);
float speed = rb.velocity.magnitude;
float timeFloatLeft = currDistFromWP / speed;
Vector3 relativeVector = transform.InverseTransformPoint(nodes[currentNode].position);
float newSteer = (relativeVector.x / relativeVector.magnitude);
Debug.Log("Steer to set: " + newSteer);
Debug.Log("Current distance: " + currDistFromWP);
if ((timeFloatLeft < 1f || Mathf.Abs(newSteer) > .5f) && speed > 5)
{
Debug.Log("Coasting...");
im.throttle = 0;
}
else
{
im.throttle = 1;
}
}
private void ApplySteer()
{
if (avoiding)
return;
Vector3 relativeVector = transform.InverseTransformPoint(nodes[currentNode].position);
float newSteer = (relativeVector.x / relativeVector.magnitude);
im.steer = newSteer;
}
Here is my waypoint updating function:
private void CheckWaypointDistance()
{
float currDistFromWP = Vector3.Distance(transform.position, nodes[currentNode].position);
//Debug.Log("Current distance from waypoint: " + currDistFromWP);
if (currDistFromWP < 1.1f)
{
im.brake = false;
if(currentNode == nodes.Count - 1)
{
currentNode = 0;
}
else
{
currentNode++;
}
}
else if (currDistFromWP < 10f)
{
im.brake = true;
}
}
I feel like I could be making this harder than I need to somehow. Or maybe I'm just needing to consider more variables. Does anyone have any tips to make this a little more tight in terms of AI logic? I'm happy to show more code if needed, but the idea is to have a Car Controller class that's used by BOTH the player and AI to DRIVE the car, and then the AI making the best decisions in a way the player would need to drive it in a separate class. The code from above is the separate AI decision making component.
When I interact with the screen the objects in my game start to stutter. My FPS is at 60 and doesn't drop but the stuttering is still prevalent. I believe my problem is how I'm animating the objects on screen(code below).If anybody could help I would appreciate it.
I have an x amount of nodes inside an array called _activePool. In the Update function I am moving the nodes x position inside _activePool, adding new nodes when the last node in _activePool position is <= 25 and removing the first node in _activePool if it's position is <= -25.
if _cycleIsActive{
for obj in _activePool{
//move the obj in _activePool
obj.position.x += Float(dt * self.speedConstant);
}
let lastObj = _activePool.last;
if (lastObj?.position.x)! + getWidthOfNode(node: lastObj!) + Float(random(min: 15, max: 20)) <= 25{
// get new obj(pattern) and add to _activePool
self.getPatternData(sequencePassedIn: selectedSeq, level: self._currentLevel, randomPattern: randomPattern());
}
let firstObj = _activePool.first;
if (firstObj?.position.x)! + getWidthOfNode(node: firstObj!) <= -25{
// remove object and return to specific pool
firstObj?.removeFromParentNode();
returnItems(item: firstObj!);
_activePool.removeFirst();
}
}
I create several arrays and add them to a dictionary
func activatePools(){
temp1Pool = ObjectPool(tag: 1, data: []);
dictPool[(temp1Pool?.tag)!] = temp1Pool;
temp2Pool = ObjectPool(tag: 2, data: []);
dictPool[(temp2Pool?.tag)!] = temp2Pool;
for i in 0... dictPool.count {
obstacleCreationFactory(factorySwitch: i);
}
}
Creating my obstacles(enemies)
func obstacleCreationFactory(factorySwitch: Int){
Enemies = Enemy();
switch factorySwitch {
case 0:
for _ in 0...100{
let blueEnemy = Enemies?.makeCopy() as! Enemy
blueEnemy.geometry = (Enemies?.geometry?.copy() as! SCNGeometry);
blueEnemy.geometry?.firstMaterial?.diffuse.contents = UIColor.blue;
blueEnemy.tag = 1;
temp1Pool?.addItemToPool(item: blueEnemy);
}
case 1:
for _ in 0...100{
let redEnemy = Enemies?.makeCopy() as! Enemy
redEnemy.geometry = (Enemies?.geometry?.copy() as! SCNGeometry);
redEnemy.geometry?.firstMaterial?.diffuse.contents = UIColor.red;
redEnemy.tag = 2;
temp2Pool?.addItemToPool(item: redEnemy);
}
default:
print("factory error");
}
}
Without being able to look at the rest of your code base it’s really difficult to guess what would be causing your issue.
If somewhere you are creating a ton of temporary objects in a loop somewhere, you might consider creating a local autorelease pool to prevent memory spikes. Here is a good article that describes why in some situations it’s a good idea.
You could also be calling some particularly expensive functions on a timer or something. It’s difficult to say.
In short, you should consider using Xcode’s Profiling tools (called Instruments). Specifically I would recommend using Time Profiler to examine what functions are taking the most time and causing those spikes.
Here is a great WWDC session video that shows how you can use the time profiler, I’d recommend regularly profiling your app, especially when you have an issue like this.
I would like to associate the same script to different empty objects I just use as placeholders in the game. The aim is to exploit their positions so that when the user touch a point in the screen, close to one of these objects, a dedicate GUI appears. The problem is that though the two objects are different their scripts seem to influence each other so that when the game is running and I touch one of these two objects both the gui appears. What am I doing wrong?
....
private var check: boolean;
var topCamera : Camera;
var customSkin : GUISkin;
function Update () {
if (Input.GetMouseButtonDown(0)){
if(Input.mousePosition.x > this.transform.position.x - Screen.width*0.20 && Input.mousePosition.x < this.transform.position.x + Screen.width*20){
if(Input.mousePosition.y > this.transform.position.y - Screen.height*0.2 && Input.mousePosition.y < this.transform.position.y + Screen.height*0.2){
check = true;
}
}
}
if(check){
//the camera zooms forward
}else{
//the camera zooms backward
}
}
function OnGUI () {
if (this.check){
var w = Screen.width;
var h = Screen.height;
var bw = 0.083;
var bws = 0.001 *w;
GUI.skin = customSkin;
GUI.Box(new Rect(w*0.6,h*0.3,w*0.38,h*0.45), "Stuff");
customSkin.box.fontSize = 0.04*h;
customSkin.textField.fontSize = 0.08*h;
customSkin.button.fontSize = 0.04*h;
textFieldString = GUI.TextField (Rect (w*0.62, h*0.39, w*0.34, h*0.1), textFieldString);
if (GUI.Button (Rect (w*0.62,h*0.50, w*bw, h*0.1), "+")) {
if (this.check){
this.check=false;
}else{
this.check = true;
}
//...
}
//...
}
This is probably not working, because you are comparing apples with oranges in your Update() function. Input.mousePosition returns the the position in 2D pixel coordinates and transform.position returns the GameObject's position in 3D world coordinates.
To check if you clicked on an object, you need to attach a Collider to the game object in question and test for collisions using a Raycast in your script. Here is the relavant example from the documentation in JavaScript:
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, 100)) {
print ("Hit something");
}
The cool thing about this approach is that we are checking for collisions between the Collider and the ray. If you only want to see if you clicked near the GameObject, just make the Collider larger than the GameObject. No need for messing around with inequalities!
If your objective is to click somewhere close to the object and not only at the object, then you have some configurations (positions of those objects in space) where there are space that are close enough to both objects for their GUI to appear and therefore you need some script to decide which one is closer.
I suggest you to implement a monobehaviour that is a singleton that would track those clicks and measure the distance of all objects, to get the closest.
Reading again your post, I think you want to get the GUI just when you click at the object, and when you do this you get both GUIs. I think that's happening because wrong calculation of the area that makes check to go true.
Can you give more details? Is there some space where there shouldn't have GUI messages when clicked, or is everything filled by those objects?