Game Maker 2 path breaks when changing rooms - path

I'm making a game in GMS 2. As part of the game, I have on object that is following a path, and I want it to continue following the same path after I change rooms. I noticed that this doesn't work - the path continues as usual, but the X and Y coordinates of the object change completely, for no reason at all - i tried this at debug mode, and at some point they just change. This only happens if I change the rooms while the path is active. This is the path creation code:
if (mp_grid_path(my_grid, my_path, x, y, dest_x, dest_y, 1)) {
path_start(path, ny_speed, path_action_stop, false);
} else {
show_debug_message("no path!!!");
}

The way I found to resolve this, is to save the path at room end, and then restore it from the same point, at room start.
At room end:
if(is_walking) { // only do this if the object is currently walking
path_end();
}
At room start:
if(is_walking) { // only do this if the player is currently walking
if (mp_grid_path(my_grid, my_path, x, y, dest_x, dest_y, 1)) {
path_start(path, my_speed, path_action_stop, false);
} else {
show_error("no path!!!", true); // if there is no path at this point, we have an error - because it existed before we changed the rooms, so it should exist now
}
}
Hope this will help anyone who gets stuck on this in the future.

Related

Tile-based movement with Lance game engine?

I'm using Lance for a game where the gameplay area is a tiled map. When a player presses the left-arrow key, their character should move one tile to the left, etc. I tried two approaches, see below, but got neither to work.
Could either approach be modified to work with tile-based movement? Or is a third approach needed? Or is Lance not suited to this kind of game?
Approach 1: Adjust the player's position directly when a key is pressed. From my GameEngine class:
if (inputData.input == 'left') {
player.position.x -= 32;
player.angle = 180;
}
While this works well for a single player, it doesn't in multiplayer. When player A moves, their position is not updated on player B's screen.
Approach 2: Set the player's state when a key is pressed:
if (inputData.input == 'left') {
player.state = 'walkLeft';
}
Then add a postStep handler in the common GameEngine class. (Adding it to Player didn't work). This code turns the player (over many steps) to face 180 degrees and then accelerates the player in that direction:
onPostStep(event) {
let players = this.world.queryObjects({instanceType: Player});
players.forEach(player => {
if (player.state == 'walkLeft') {
if (Math.abs(player.angle - 180) > 2)
player.turnLeft(2);
}
else {
player.accelerate(1);
player.state = '';
}
}
})
}
With this approach, if a player presses the left arrow key, their angle changes as expected at first, but the acceleration and movement is erratic. Also, Player A's position appears different on their screen vs the screen of Player B.
The Spaaace demo is the base for my project, so my project uses the same bending, physics engine, etc.
The first approach is better. The Brawler game in the sample collection does exactly what you describe. You can look at the BrawlerGameEngine.js code in https://github.com/lance-gg/tinygames/tree/master/brawler
Make sure that the action is processed in the method
GameEngine::processInput(inputData, playerId)

How do I only respond to touches within a UI Image?

I have been wracking my brain and using every Google search phrase I can think of and have yet to find a solution.
I have a Unity app with a 3D scene and UI elements that float over it. There is one UI element that is an image of a protractor. That image needs to be drug around the scene, rotated, and scaled. All of that works, the only catch is that is doesn't matter if the user touches the protractor or somewhere else, the protractor always reacts.
I started by looking for something along the lines of Swift's someCGRect.contains(someCGPoint) so that I could ignore anything that isn't in the bounds of the protractor. Image doesn't seem to have such a property so I did lots of other searching.
I finally found this video; https://www.youtube.com/watch?v=sXc8baUK3iY that has basically what I'm looking for… Except is doesn't work.
The video uses a collider and rigid body and then in code checks to see if the collider overlaps the touch point. Looks like exactly what I need. Unfortunately, no touches ever overlap with the collider no matter where they are. After some Debug.Log I found that the extents of the collider are reported as (0, 0, 0). This is clearly why none of the touches overlap with it, but I can't figure out how to make the extents be anything other than 0.
Here is the info from the colliders and rigid body attached to the image:
Box Collider 2D:
Used by Composite: true
Auto Tiling: false
Offset: (0,0)
Size: (1,1)
Rigidbody 2D:
Body Type: Kinematic
Material: None (Physics Material 2D)
Simulated: true
Use Full Kinematic Contact: false
Collision Detection: Discrete
Sleeping Mode: Start Awake
Interpolate: None
Constraints: None
Composite Collider 2D:
Material: None (Physics Material 2D)
is Trigger: false
Used By Effector: false
Offset: (0,0)
Geometry Type: Polygons
Generation Type: Synchronous
Vertex Distance: 0.0005
There is a button that turns the protractor on and off by use of the following code:
public void toggle() {
this.enabled = !this.enabled;
this.gameObject.SetActive(this.enabled);
}
The protractor starts life visible but Start() calls toggle() straight away so the user sees it as starting out off.
This is the code that performs the test to see if the touches should be responded to:
void checkTouches() {
if (Input.touchCount <= 0) {
return;
}
bool oneTouchIn = false;
Collider2D collider = GetComponent<Collider2D>();
Debug.Log("🔵 The bounds of the collider are: " + collider.bounds);
// The above always logs the extents as (0,0,0).
foreach (Touch touch in Input.touches) {
Vector2 touchPos = Camera.main.ScreenToWorldPoint(touch.position);
if(collider.OverlapPoint(touchPos)) {
// Since the extents are all 0 we never find any overlaps
oneTouchIn = true;
break;
}
}
if (!oneTouchIn) {
return; // Always ends up here
}
// We must have at least one touch that is in our bounds.
// Do stuff with the touch(es) here…
}
I've been doing iOS development with Objective-C since the SDK was released and with Swift since it come out but I'm very new to Unity. I'm sure the issue is me missing something silly, but I can't find it.
Does anyone know what I'm missing to make the current version work or an alternate way of only responding to touches that are in bounds?
Image doesn't seem to have such a property
No the Image componemt itself doesn't have that ...
But the rect property of the RectTransform component each UI GameObject has.
It is called Contains. So you could do e.g.
RectTransform imgRectTransform = imageObject.GetComponent<RectTransform>();
Vector2 localTouchPosition = imgRectTransform.InverseTransformPoint(Touch.position);
if (imgRectTransform.rect.Contains(localToichPosition)) { ... }
Alternatively you could use the IPointerEnterHandler and IPointerExitHandler Interfaces in a component on the target Image like e.g.
public class DragableHandler : MonkBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public bool IsHover {get; private set; }
//Detect if the Cursor starts to pass over the GameObject
public void OnPointerEnter(PointerEventData pointerEventData)
{
//Output to console the GameObject's name and the following message
Debug.Log("Cursor Entering " + name + " GameObject");
IsHover = true;
}
//Detect when Cursor leaves the GameObject
public void OnPointerExit(PointerEventData pointerEventData)
{
//Output the following message with the GameObject's name
Debug.Log("Cursor Exiting " + name + " GameObject");
IsHover = false;
}
}
and than in your script check it using
if(imageObject.GetComponent<DragableHandler>().IsHover) { ... }
just also make sure that we the EventSystem you also add Touch Input Module and check the flag Force Module Active.

How do I detect if a number is a decreasing or increasing number? iOS

I'm using a SpriteKit game engine within XCode while developing a game that bounces a ball and platforms come from the sky and the objective is to bounce on the platforms to get higher. I need to add a velocity to the ball when it falls down + comes in contact with a platform. I'm having trouble trying to detect the balls Y position. I had something like this in the update method but nothing happens... I'm open to suggestions.
//The value of the _number instance variable is the Y position of the ball.
if (_number++) {
NSLog(#"UP");
}
if (_number--) {
NSLog(#"DOWN");
}
You can see a node's position by using code like this:
if(myNode.position.y > 0)
NSLog(#"y is greater than 0");
If you want to check a node's current speed (vector) you can do it like this:
if(myNode.physicsBody.velocity.dy > 0)
NSLog(#"Moving up");
if(myNode.physicsBody.velocity.dy < 0)
NSLog(#"Moving down");
Remember that position and speed (vector) are not the same thing.
You need to read the SKPhysicsBody docs to understand about CGVector and other important issues.
Alright, this:
if (_number++) {
NSLog(#"UP");
}
if (_number--) {
NSLog(#"DOWN");
}
doesn't work to do anything. It shouldn't even run. I don't why it doesn't give an error.
number++; is a simplified form of
number = number + 1;
You can't place it in an if statement.
First make the variable #property int ypos in your header.
Then every update compare the current y to the ypos.
After comparing, save the current y to ypos.
Place this in your Update method.
if (ball.position.y > _ypos)
{
//going up
}
else if (ball.position.y < _ypos)
{
//going down
}
_ypos = ball.position.y;
P.S. I haven't had access to a computer so the formatting might suck from my phone

How do I calculate the speed of which a user drags an image?

I have an image that the user can drag to the right and it will spring back when the user releases it. I want to execute some code when a user drags it quickly and releases it. Now I have a very awkward requirement that the user can drag the image, then keep it still for any length of time (for example 5 seconds), then drag it quickly and release it. As long as the image is moving above a certain speed when it is released, it will execute the code. If it falls below the minimum speed, it executes some different code. So that means I can't calculate the length of time between the beginning of the gesture and the end and execute the code depending on the length of time. What can I do? I guess I somehow need to know the speed at which the image is moving in it's last 500 milliseconds before the gesture ends. However I've hit a brick wall figuring out how to do that. Any help would be greatly appreciated.
Can you please include an explanation and possible example code with your answer as that would be a great help.
If you get the start X,Y coordinates of when the image is dragged, and the X,Y coordinates for when the mouse is released, you can use pythagoras' theorm to calculate the distance between the two points: http://en.wikipedia.org/wiki/Pythagorean_theorem
Also, if you start a timer when the mouse is moved (and mouse button is down), and stop it in the mouseup event, you can calculate the speed using the time and distance (speed = distance / time)
edit following comments:
point delayedMousePos;
point previousMousePos;
bool secondDrag = false;
bool isStopped = false;
var timeFirstStopped;
var positionCount = 0;
array previousMousePositions[3];
// timer which monitors mouse position (set to an interval of say, 10ms)
function timerMonitorMousePos_Elapsed() {
point currentMousePos = getMousePos();
if (isStopped == false) {
if (positionCount >= 2) {
array_shift(previousMousePositions); // remove the first element of the array and move everything down to reindex numerical array to start counting from zero
positionCount = 2; // keep positionCount within array bounds
}
previousMousePositions[positionCount] = currentMousePos; // add the new position to the end of the 'stack'
positionCount++;
}
if (currentMousePos == previousMousePos) { // start check for stationary
isStopped = true;
if (timeFirstStopped == null) {
timeFirstStopped = NOW();
} else {
if (NOW() - timeFirstStopped >= 500) { // we have been stopped for at least 500ms (assumes time is counted in milliseconds)
secondDrag = true;
// previousMousePositions[0] = the mouse position 30ms before the mouse stopped
}
}
} else {
isStopped = false;
timeFirstStopped = null;
}
previousMousePos = currentMousePos;
}
I wouldn't use a timer. I would just save the starting date/time along with x,y position when the dragging starts.
When the dragging has ended, save the ending date/time and position. From those information, I can calculate the distance in pixel and duration in milliseconds.
After searching some more on the internet, I finally answered my own question.
I worked out what I needed to do:
My UIPanGestureRecognizer:
- (IBAction)handlePan3:(UIPanGestureRecognizer *)recognizer3
Get the velocity of the users finger moving across the screen:
CGPoint vel = [recognizer velocityInView:self.myView];
Then:
if (vel.x > /*value*/) {
// Your code
}
I was about to give up, but no! I got there in the end. Thanks for everyones help. I've upvoted one or two answers because they were helpful. bobnoble actually gave the suggestion to use velocityInView and I found this other stack overflow question which gave me the info I needed: iOS - Making sense of velocityInView on UIPanGesture

Updating amount of "lifes" that the player has

I'm making this small flash game where a user has to fly and try to dodge stuff... when the user hits an object it has to remove one of his lives that is shown by a feather.
Everything of the game works perfectly however the feathers don't want to update on the frame (they keep showing 3 which is the starting amount of lives).
This function adds the feathers (illustrating the lives of the player).
var levens = 3;
stage.addEventListener(Event.ENTER_FRAME, leeft);
function leeft(evt:Event):void {
for(var i = 0; i < levens; i++)
{
var v:MovieClip = new feather_mc();
addChild(v);
v.x = 50 + i*12;
v.y = 382;
}
}
Following function is a hittest object function that updates the variable "levens"... as soon as the user hits an object
function raak(evt:Event):void {
if(eagle_mc.hitTestPoint(evt.target.x,evt.target.y, true)==true)
{
removeChild(MovieClip(evt.target));
evt.target.removeEventListener(Event.ENTER_FRAME,raak);
levens--;
if(levens==0)
{
gotoAndStop(41);
}
}
}
You are constantly adding new feathers since the "leeft" function is called on each frame. The result is that the feathers are stacked on top of each other, so if you remove one, the other at the same location appears. I suppose you'll want to execute this method once during initialization.

Resources