Install Steam
login
|
language
简体中文 (Simplified Chinese)
繁體中文 (Traditional Chinese)
日本語 (Japanese)
한국어 (Korean)
ไทย (Thai)
Български (Bulgarian)
Čeština (Czech)
Dansk (Danish)
Deutsch (German)
Español - España (Spanish - Spain)
Español - Latinoamérica (Spanish - Latin America)
Ελληνικά (Greek)
Français (French)
Italiano (Italian)
Bahasa Indonesia (Indonesian)
Magyar (Hungarian)
Nederlands (Dutch)
Norsk (Norwegian)
Polski (Polish)
Português (Portuguese - Portugal)
Português - Brasil (Portuguese - Brazil)
Română (Romanian)
Русский (Russian)
Suomi (Finnish)
Svenska (Swedish)
Türkçe (Turkish)
Tiếng Việt (Vietnamese)
Українська (Ukrainian)
Report a translation problem
In the event of a collision at the point you're moving to, check to see if there's a free point in either perpendicular direction within a margin of error. The most accurate way to check for this would probably be a for loop, but the quickest way to just check if the concept works would be a simple "if collision at x, try x+3 and then x-3, move to whichever's open." This falls short if you have a wall too close or a thin enough object that the player could pheasibly wrap to either side of it hitting it from the middle, but for general situations it should work fine.
That said, if the instance id of the wall you've bumped into would be beneficial, you could try using instance_nearest() or some similar method, which returns the id of whatever it finds.
Here's what I have for my left key input
"wall_buffer=20 //The number of pixels my character is to the edge of an object.
key_left
{
if !place_meeting(x-speedup,y,par_wall) x-=speedup; //If there's not a wall to the left, move left.
if place_meeting(x-speedup,y,par_wall) && place_free(x-12,y-wall_buffer) y-=speedup;//If there's a wall to the left AND there's a space free above and to the left, move up.
if place_meeting(x-speedup,y,par_wall) && place_free(x-12,y+wall_buffer) y+=speedup;//If there's a wall to the left AND there's a space free below and to the left, move down.
};"
It's actually kind of working the way I want it to, though I'm sure this isn't the most efficient way of doing this. My character moves unless there's a wall in front of him. If there IS a wall in front of him, AND if there's a place free at a steep diagonal (the, the character moves along the wall until the path is clear.
The trouble now seems to be coming in with:
a.) Skirting around circles (the behavior for whatever reason seems to work best on square objects or objects with square sprite/collision masks).
b.) The character doubles in speed if the player is holding a diagonal at an object edge, because it's taking speed from both the direction behind held AND the wall hugging code.
c.) Right now it's having trouble for some reason with objects that are too small.
I suppose the obvious workaround would just be that objects would have to be of a certain size for these commands to work. It's also been a bit tricky to figure out
What I suppose would further complicate things is that this is all just code as it pertains to my par_wall object. This is just a parent object that all of my 'walls' inherit (which at some point I suppose would include invisible tiles behind things like couches, tables, etc). Since I'm just kind of doing testing, I have this as a parent to a couple of different objects. If this was a real game, I suppose I would want to have different "wall hugging" behaviors on other objects - people for instance (where maybe I don't want such forgiving wall hugging behavior).
Edit: I've toyed with this for the past hour but still can't figure out how to resolve some issues.
1.) My guy keeps getting stuck on the corner of things. My current code is all for when you're going down, up, right, or left INTO the edge of something...but when you go in at a diagonal in the opposite direction (hard to articulate...may have to illustrate), things get funky.
2.) My guy still whips around corners. Right now, if he hits the edge, he'll start moving along an axis at his speed. However, if I'm holding two directions, the game takes THAT speed, PLUS the speed of the wall hugging, so he kind of whips around the edge for a moment. I want to be able to say "When you're holding Left and Right and you hug the corner, speed = speed/2." Maybe I'll have to make the wall hugging code a variable, and then say "If wall_hug_diagonal, speed = speed/2."
For the most part, it works great. if you run towards an edge, it behaves exactly the way I want it to. He even slides along large circles once he reaches a certain point on the circle. It's when you start running at diagonals that things get bizarre.
Purely for the sake of code efficiency, you might want to consider changing some of your ifs to else ifs and utilizing some curly braces, and I'll explain why. Presently your code is basically doing this:
(My directions don't match yours completely here, because I guess I just find it easier to think in terms of moving north than anything else.)
There's a couple problems here, but the biggest one is that you'll always be going through all three checks; what may well be causing your problems with thin objects is that a thin enough object would return true on both checks on seeing if there's a place free to either side. The quickest solution there would be to convert the conditions into one logic tree:
In this case, the two free position checks are only run if a wall is detected in the first place, and if the first returns true, the other is ignored because a solution has already been found. If no wall was detected to begin with, you simply move forward like normal. On top of avoiding conflicts, the only logical bit the program needs to process in this case for most steps will be "is there a wall?", which helps keep things running pretty smoothly.
Another thing you might want to try to help with the diagnal movement might be checking if the player's moving diagonally at all before running the slide checks, possibly opting to ignore them, say, if a perpendicular key is being held down. So, assuming we're working with the up key here:
This still won't be perfect, but it'll stop the speed doubling. The problem is that if a wall is hit by either key's direction check, the player won't move at all in that direction unless you do *seperate* checks for diagonal movement entirely, at which point you might be better off moving this all into the Step event and working out the details there lest this become a logical nightmare, though an alternative might be to do different checks for up and down than left and right; in left and right's logic, you could put the entire thing in a conditional that it only runs if neither up or down is pressed, and then keep the diagonals restricted to the keys assigned to vertical movement so you don't get any weird doubling or conflicts in your collision checks.
EDIT: you updated your post before I finished mine, but hopefully this still helps a little or gives you some decent ideas.
Are you saying I shouldn't be doing this in the Step event? That is currently where I have this code. Where else would I be putting it? Aren't these all checks that need to be done every frame?
if and else if are both super useful things, and else can be as well when used properly. Basically, if you cast an if condition and it returns true, everything after that statement in the brackets (or just for the rest of the line, if you're only performing one statement) gets executed, whereas anything after "else" occurs in the opposite scenario. It's a bit hard to pull off on the single-line instructions, especially if you want to come back to your code later and still be able to read it, but last I knew you could still do something like
You'll probably want to look into switch statements, as well. I can't see getting far with an RPG project without at least knowing about those.
Looking at the Up key again, I have the following:
Analyzing it, you get something like this:
if (not left) or (not right) ...
So that if the player is pressing left, you'll get
if (FALSE) or (TRUE)
Because the right key isn't being held in this scenario, the second statement returns true, so the or statement will return true as a whole. Meanwhile with and, you'd get
if (FALSE) and (TRUE)
and requires both statements to be true to advance; in this case, that's not what we're getting, but if we let go of both horizontal keys...
if (not left) and (not right)
if (TRUE) and (TRUE)
In less words, with the or statement, if any one thing is true, then the entire statement confirms as true. With the and statement, you're getting the opposite: if anything is false, the entire statement comes back as false.
As a further example, you could check for an idle animation like this:
if (not left) and (not right) and (not up) and (not down) then idle
and the second any key is pressed, say our present favorite to pick on, the up key:
if (TRUE) and (TRUE) and (FALSE) and (TRUE)
the entire thing comes out to false, simply because one condition returned as such.
As an aside, if the pseudo-code starts driving you nuts just let me know. At this point most of what we've been looking at is logic more than any specific function, so I've been keeping to it simply because I find it a bit clearer to communicate with. That, and it keeps things a little more hands-on and retainable. ;)
And lo and behold, it worked like a charm. There is no speed doubling anymore, whatsoever. The movement feels more forgiving and fluid. I'll see if I can paste a link to my progress on the Workshop.
Thank you so so so much! I feel like I can finally move on to some other things now. I suppose what I'll really have to get used to is the logic trees. If I ever have something that has a lot of conditions, I'll have to maybe work backwards (if I want someone to run....maybe start with that....but then what if there's a wall....what if there's a person blocking the way....what if there's this, what if there's that,etc etc)
I feel like I owe you already! Here's a link to my progress on Steam Workshop (forgive the awful art...I'm a professional illustrator but I'm just getting the basics down, haha) - http://steamcommunity.com/sharedfiles/filedetails/?id=222634895
I will advise that you do your best to avoid persistent rooms, as one of the only GM RPGs I know of that reached completion used those (and I believe unique objects for each and every NPC and item box in the game) and wound up having pretty exhorbant save files by the point you got near the end, to the extent that at the time many people couldn't finish the game because the time it took GM to write the file resulted in Windows flagging the app as not responding. I used a method to save that was outdated with GM:S, so I think we'd both be well advised to learn to use .ini files for saving; it doesn't seem particularly difficult, and it's easier to test sooner rather than later.
I've done a lot of RPG dabbling in GM (and consequently have learned arguably more don'ts than dos), so if there's anything you need help with down the line feel free to ask. :)
I did have one question real quickly though...is it bad form to have objects exist outside of a room? I ask because I have some "Room Change" objects for when my character leaves certain edges of the screen (or eventually, a door in front of a house). Since I want the room change to occur when the character gets to the edge of the screen, I have obj_roomchange right outside my room (with a target room/position in obj_roomchange's creation code). Is this sloppy Game Maker usage, or could it possibly cause any problems with memory or resource management? It sounded way easier for me to do it this way, rather than to place my obj_roomchange's inside the room, and then have to figure out how to not initiate the room change until a certain point.
If it's not a problem to have these obj_roomchange objects outside the room, then disregard :)