I love the smell of UnrealEd crashing in the morning. – tarquin
Difference between revisions of "User:DalinSeivewright/Old Developer Journal"
(Mmm.) |
m |
||
(2 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | {{classbox| Welcome To | + | {{classbox| Welcome To Dalin Seivewright's (Archived) Developer Journal.}} |
{{classbox| Journal Entries are sorted from newest to oldest by date.}} | {{classbox| Journal Entries are sorted from newest to oldest by date.}} | ||
Line 563: | Line 563: | ||
<div class="hidden-block"><span class="hint">'''''Example Image:'''''</span><div class="hidden"> | <div class="hidden-block"><span class="hint">'''''Example Image:'''''</span><div class="hidden"> | ||
− | [[Image:Legacy_Myth_RotationalWeight.jpeg|]] </div></div> | + | [[Image:Legacy_Myth_RotationalWeight.jpeg|Legacy_Myth_RotationalWeight.jpeg]] </div></div> |
And actually, the more I think about it the more tasty it sounds. This could actually solve the problem of the bot having to know '''exactly''' where the player is. If a player was behind a bot and the bot was aware of this, the bot would spin around and start shooting. Us human players (or at least those of us without aimbots...) have to do vector/angle calculations in our head (really, we do!) so we can aim and fire at our opponent and hopefully if our hand/eye coordination is good (and the computer/server isn't lagging) then we would hit our opponent. However, we SEE the opponent, we KNOW where he is, but we only know a rough estimation. We don't know the exact vector of our opponents. Epics bots, well, I'd hate to being them down, but they're aimbotting smacktards. They pretty much know the -exactly- location of all of their opponents. The only reason why, as Eric has previously stated, they don't get you 100% of the time is because of the AimError on all the weapons which throws their shots off. This proposed rotational weight system could actually help prevent that... or actually, I guess it would create a new kind of 'aim error' but it would be more believable. When the bot turns around to shoot at the opponent, based on the direction of the player and the bot, it would assign a weight system to its rotation, the height 'weight' being the direction the opponent is most likely to end up being at when the bot fires a shot. This wouldn't be exact though (as humans don't have the exact location either, just guestimations) and so the bot will have to 'home-in' on the direction. I'm going to stop there before I get ahead of myself (again...) I just started thinking about having the bot learn from the opponent and save directions that the opponent will most likely come in to his FOV... but lets not go there. | And actually, the more I think about it the more tasty it sounds. This could actually solve the problem of the bot having to know '''exactly''' where the player is. If a player was behind a bot and the bot was aware of this, the bot would spin around and start shooting. Us human players (or at least those of us without aimbots...) have to do vector/angle calculations in our head (really, we do!) so we can aim and fire at our opponent and hopefully if our hand/eye coordination is good (and the computer/server isn't lagging) then we would hit our opponent. However, we SEE the opponent, we KNOW where he is, but we only know a rough estimation. We don't know the exact vector of our opponents. Epics bots, well, I'd hate to being them down, but they're aimbotting smacktards. They pretty much know the -exactly- location of all of their opponents. The only reason why, as Eric has previously stated, they don't get you 100% of the time is because of the AimError on all the weapons which throws their shots off. This proposed rotational weight system could actually help prevent that... or actually, I guess it would create a new kind of 'aim error' but it would be more believable. When the bot turns around to shoot at the opponent, based on the direction of the player and the bot, it would assign a weight system to its rotation, the height 'weight' being the direction the opponent is most likely to end up being at when the bot fires a shot. This wouldn't be exact though (as humans don't have the exact location either, just guestimations) and so the bot will have to 'home-in' on the direction. I'm going to stop there before I get ahead of myself (again...) I just started thinking about having the bot learn from the opponent and save directions that the opponent will most likely come in to his FOV... but lets not go there. | ||
Line 1,097: | Line 1,097: | ||
The main problem was that my player view's yaw was wrong. I made some lovely images to clarify. | The main problem was that my player view's yaw was wrong. I made some lovely images to clarify. | ||
− | [[Image:Legacy_Myth_RotationsA.jpeg|]] Figure 1 | + | [[Image:Legacy_Myth_RotationsA.jpeg|Legacy_Myth_RotationsA.jpeg]] Figure 1 |
− | [[Image:Legacy_Myth_RotationsB.jpeg|]] Figure 2 | + | [[Image:Legacy_Myth_RotationsB.jpeg|Legacy_Myth_RotationsB.jpeg]] Figure 2 |
Figure 2 is where it was all wrong. The map I use for testing purpses is a single '''vertical''' room not a horizantal room and my player view was set to make it look like it was actually horiztonal. This played havok with my rotation and caused a lot of things. After I fixed this, everything miracoulously fell into place. Anyways... | Figure 2 is where it was all wrong. The map I use for testing purpses is a single '''vertical''' room not a horizantal room and my player view was set to make it look like it was actually horiztonal. This played havok with my rotation and caused a lot of things. After I fixed this, everything miracoulously fell into place. Anyways... |
Latest revision as of 21:12, 24 April 2008
Contents
- 1 Journal Entries
- 1.1 January 26th, 08
- 1.2 Monday, December 24th, 07
- 1.3 Tuesday, December 11th, 07
- 1.4 Saturday, September 29th, 07
- 1.5 Tuesday, September 25th, 07
- 1.6 Thursday, September 13, 07
- 1.7 Wednesday, September 11, 07
- 1.8 Saturday, September 08, 07
- 1.9 Wednesday, September 05, 07
- 1.10 Sunday, September 02, 07
- 1.11 Monday, August 27, 07
- 1.12 Tuesday, August 21, 07
- 1.13 Monday, August 20, 07
- 1.14 Sunday, August 19, 07
- 1.15 Thursday, August 16, 07
- 1.16 Monday, August 12, 07
- 1.17 Saturday, August 11, 07
- 1.18 Monday, July 23, 07
- 1.19 Saturday, July 14, 07
- 1.20 Tuesday, July 10, 07
- 1.21 Saturday, July 07, 07
- 1.22 Thursday, July 05, 07
- 1.23 Tuesday, July 03, 07
- 1.24 Friday, June 29, 07
- 1.25 Wednesday, June 27, 2007
- 1.26 Monday, June 25, 2007
- 1.27 Wednesday, June 20, 2007
- 1.28 Tuesday, June 12, 2007
- 1.29 Saturday, June 09, 2007
- 1.30 Wednesday, June 06, 2007
- 1.31 Saturday, June 02, 2007
- 1.32 Friday, June 01, 2007
Journal Entries
January 26th, 08
Mmm. Happy Late (x30) New Years. I'm not sure if I mentioned it but I'm back in school again. Since January 7th to be exact. I'm not sure how I feel about it but anyways.
I haven't touched UnrealScript since then. As common for me as that is, I'm kind of dissapointed with myself. Again. In fact, it doesn't look like I'll be working on a major OR minor UnrealScript project for awhile. I did play a decent flash-based 2d game last night though. It was called Smiley Wars, and while the gameplay itself wasn't all that fun, the idea behind it (minus the Smiley's) was a decent one. Games like it have been done before, even multiplayer ones, but this one had a map editor which sparked interest in the first place. Anyways, this game is a Deathmatch game based on 'levels' built on triangles as well as other non-collision objects. Anyways, the map editor wasn't the greatest thing in the world but it got the job done and let you create semi-awesome levels, given the restrictions of the engine itself.
So given that my 'first' language is UnrealScript I tend to prefer writing even pseudo code in UScript form and I've been toying with creating a 2D game like that... except of course with a big more features and a speed boost. Given that I hate working with Flash, I don't know enough of Java, and I don't have my VBasic editor anymore, I'm going to have to work up a concept in UScript form, which will be fun. I don't imagine anything workable coming out of it but we'll see. I may switch to a different language later on.
There's one thing I sort of despise about UnrealScript though. The process for making even the smallest mutator seems to take forever and includes several steps. I think thats one factor associated with me stopping certain projects. You need to make a folder with the name of your package, then within that a folder called classes. Then if you're making a new Gametype you need to find the appropriate GameType to extend, ovveride the appropriate functions (which could take awhile to do if you want certain functionality excluded while keeping certain functionality dependent on the previously excluded functionality. Then comes the default properties which you need to change, at the very least with the Game Name and Description. More so if you're going to be using custom maps, custom pawns, player controllers and AI controllers. Further more in your custom classes, you need to ovveride certain functions and default properties in them.
So, IMO, its just a big huge mess. I haven't touched UT3 yet, fearing that it would be even more of a task. I don't use an IDE either mind you, but thats only because I find most of the IDE's I've tried to be a tad too 'messy'. The only think I code with is UCC and ConText.
At any rate, you might end up seeing my concept ideas on this page from time to time. Anywhere from "I wonder how to do that" to "This is concept code. I'm putting it up here but please don't explicitly steal with like those Flash-game fan boys out there."
That is all.
Monday, December 24th, 07
Merry Christmas, first of all if I haven't said it already. Last night was my first normal sleep since I've quit my job. Previously its just been getting up at 12-4 pm, going to sleep at 8 am, and that has really thrown my sleep pattern off and I think I've been getting slightly unhealthy due to it. This week is filled with Christmas supper and what not, so it will be good. I won't be getting very many presents. Not that it truly matters to me (Two christmas' ago, I stated that I want nothing to do with Christmas presents any longer but sure enough I've still be getting a few). I've been mostly playing Guild Wars (which for some reason since Factions came out I have been wanting to buy all of the Campaigns and what not but haven't really 'gotten' into it until a couple of weeks ago. Now I'm actually concerned with how my 'build' fares. Previously, I found all of the talk of 'builds' and such to be annoying and contrary to the intent of the game. I was wrong.
Anyways, I've decided that I need to start from the beginning and go back to the only gametype I've ever released. At that time it was basically just copy and pasted code from Invasion with workarounds to support two teams that battled out for the most points. Unfortunately, I decided that it would be 'cool' to add an option to set the default player health. I had the health value set in my .ini and I didn't give it a second though until after I released it. At this time I had deleted my config and realized that whenever I tried to play a game of Team Invasion, I would not be able to move and shortly after the game would crash. This is when I realized that setting a players health to 0 without killing them is a really bad thing. The default value to set the health at was at 0 and so, if anyone picked up the gametype and didn't see the config option, they would mostly pass it off as a bugged crappy gametype.
I did fix this bug but had problems uploading it to Fileplanet and so, I gave up on it. Shortly after that, I had a hard drive failure and all of it was gone anyways. I have attempted to remake the gametype (and this time from scratch using my own code and so fourth) but every time I did so I stopped working on it because of boredom, as I've already made something like it. I'm making another attempt at it. The note to self was to remember to make a portable warp portal system, similar to the Phase Gates in natural-selection complete with a location menu. So, you would only be able to place once warp portal per zone (per team of course) and when you used said warp portal a selection menu (like the 'v' menu in ut) and it would give you a list of the zones you can warp to that have active warp portals in them. The warp portals can be destroyed. I was thinking these would be cool for larger maps but I'm not sure how useful they would be for a round of team invasion, so I would have to make some sort of strategic signifigance for them as most DM maps aren't very big and using CTF/BR maps doesn't make very much sense as the monsters would spawn on both teams side so there would be no point to kill the players on the opposite team because both teams would still get just as many kills.
That gets me thinking too. In the first iteration of Team Invasion, players could kill monsters and the players on the other team. The point of which was to get big points for killing monsters and getting the other team out of an area with lots of monsters so your own team can get the points for killing them. However, when you died you respawned instantly so you could get back to the spot you were killed at relatively quickly. I guess I'll have to put in a respawn timer like Assault has. I guess that also creates a strategic signifigance for warp portals. Hmph. Food for thought I suppose.
Tuesday, December 11th, 07
Oh boy. Its been awhile hasn't it. I can safely say that I have made zero progress on Icarus. In fact, after moving into the new house and getting settled, I figured it would be a great idea to start working on it again. After opening it up in my text editor, and looking through the code, I decided against it. So Icarus is yet another project dedicated to the learning side of things. I did however, start working on something similar to the project I started with. This time I have an actual mouse driven hud thats works though and that I can use to scroll around a given map. What I'm trying to do is use the mouse to place objects on the map. That part works alright, but so far I haven't been able to line up the mouse with the object properly. In fact, what I thought was a flaw in the code, is actually how it would look in real life.
That is, when the mouse is in the center of the screen (and the camera to the level is about 2000 UU's above the object you want to place) then the object appears directly under the mouse. However, when you move the mouse further from the center, the mouse and object no longer line up. I haven't the slightest of ideas on how to 'fix' this 'problem' but it makes placing structures fairly annoying when the object isn't where your mouse is. My problem is that the mouse is drawn on the Canvas and is completely different from a vector. I have the location of the mouse in vector form but that doesn't help me much seeing as the mouse is already drawn on screen and I wouldn't know how to make the neccesary changes to the position of the mouse so that it is always on the object.
Meh. I'll figure it out eventually. Or just stick to a mouse driven 'hero' that'll save the day.
Saturday, September 29th, 07
I've hit another snag. This one can neither be avoided or reworked. My laptop I've found out, has a video card that doesn't really support UT2004. Its sort of funny actually and mostly visible from within the editor which is primarily the problem. When you go 'outside' of the map in UED, the walls are supposed to cut away. It seems that when I zoom out, the walls do not cut-away and appear as solid walls that you can't see through. I can work around this, to an extent, but there are other twerks with it that cause the most problems, add to the fact that A. this IS a laptop and B. the monitor on THIS laptop DOES suck for level editing... Then theres the apparent lack of FPS that I seem to get whenever I look at something that would be rendered. Looking into the sky with nothing in your LOS blocking your vision from the skybox gives you roughly 60 fps (which is great, my desktop does less) but as soon as you look at anything else it drops down to 10-20 FPS which isn't fun for A. Online play, B. AI Testing, C. Level Testing or D. Any fun. I haven't really noticed this before unfortunately is because most of my testing has been done on my desktop anyways. This is a problem because the ideas I've had would require 90% of it to be done within levels due to either custom actors that need to be set up or levels in general that require the sort of environment I'm looking for. I really don't think I'm going to be getting any work done, at least not for awhile. I'm living in my Aunties spare bedroom until we find a new house and I still need to find room for my desktop. I really need it setup, at least long enough so I can get some files I need off of it. In the meantime... well... I'll be playing F.E.A.R. (which runs quite well, while UT2004 does not....) and I recently lamed out and bought myself Pokemon Diamond... Don't ask. In fact, I'm reminded of why I quit playing Pokemon. The new Zelda is coming out Tuesday though. This boy is excited.
Tuesday, September 25th, 07
I'm moving out of my house on either Wednesday or Thursday and frustration with that fact and various other things has the result of not that much work getting done on this project. My main computer has been decomissioned until I move into this new house (which of course, I don't know what new house I'll be getting...). That puts a serious hamper on my creative juice because most of the things that would inspire me are not on this laptop.
This AI project has frustrated me a lot though, as you may know. I've taken various breaks that have helped a lot, for example, working on a level that for now I am quite satisfied with, at least when I put into perspective my actual skill with regards to level designing. I think the main problem I have is being able to visualize everything wonderfully but I still don't have the technical skills to put it out there. I'm okay with that, my skill has improved a lot since my days of Unreal level designing, which in case you were wondering, were much more fun but a lot less 'beautiful'.
I guess the major issue with this AI project is my need to do things my way. Not saying that doing things 'my' or 'your' way is completely wrong, but if you're looking for compatibility well, then it usually is. My desire to sub-class directly from actor has led to more than one complication. For one, I can't really use any of the movement code inherent in classes like Pawn. Any game related things like death/score/etc look for a Pawn or a Controller, both of which I do not have, to set things up. Not to mention I have to re-invent the wheel even more by mimicking the way the Pawn works so my bots don't do anything that players cannot, like jumping with a z-velocity of 512 rather than 340, or jumping from a really high tower and surviving when normally you would die. Sometimes its easy to do this, sometimes its not so easy.
That being said, it leaves me Three (3) options.
The first, is to keep chugging along like I have been this past couple of months and continue for what most likely will be 6+ months of work, all of which I could have avoided by subclassing the appropriate things and spending a month of overriding and bug fixing.
The second, is to stop work on the AI all together.
The third is to start from scratch and subclass class X,Y,Z as I need them, and use states, like apprently, any sane one would do.
But wait! There is a fourth option! Yes a fourth option. What is this fourth option you ask? Well, it involves having to add/take away X amount of code from the existing code. It involves not hooking into the existing game but rather creating a new Gametype entirely. It will eventually involve faking the Spider physics type. No I won't be making a Spiderman mod.
Actually, I don't know exactly what I'll be doing. I had my heart set on something like Invasion/Alien Swarm, but that can change at any time. I think the AI the way it is now is much more fitting for something like this, aliens/creatures/monsters/ownageness. I had the image of a couple of aliens jumping on and from walls and stuff as the player runs through the hall way and as he's leaving the hall way he notices a gas line on the walls and he dives, turns and shoots the gas line, igniting the baddies. It would resemble a 'sci-fi horror' flick. I also had images of you opening a door and a monster jumping out at you only to disentigrate akin to F.E.A.R. I don't know, its all just musings right now really. I'm going to see if I can fire up my Desktop at my temporary home to get my map and all my files off of it so I will be able to finish that first while I do up some concept stuff for this idea. It really would be a great implementation for the AI in its current state.
Thursday, September 13, 07
Goal #1 is completed. I just set the physics to Phys_Walking in the Landed function. I forsee needing that function for other things as well. Instead of moving on to Goal #2, I think I may skip to implementing some jumping, dodging and some random 'logic' stuff.
Wednesday, September 11, 07
A few minor, but important things I've discovered. Firstly, there is little to no difference between how Epic gets their pawns moving and how I'm getting my bot moving. I found this out by restricting movement of my bot to only the X axis and sure enough, its Veloctiy and my own Velocity were both 440. So the bot wasn't moving too fast, the animation rate was just too fast and I don't really have anything significant in my test maps to determine how fast its moving. I fired up CTF-FaceClassic and everything looked okay. Secondly, apparently, my bots don't really want to spawn at the exactly location of the PlayerStart. I haven't looked into the cause of this, but something tells me when bots spawn inside the flag room (in Face, PlayerStarts are only outside behind either tower).......
Forget point two. The reason they don't spawn on the playerstarts is beacuse they are being spawned on NavigationPoints so... My bad. On to point number two again though... The design of my previous mod idea has come back to haunt me again. I didn't implement any z-axis movement at all into the bot so its kind of funny to watch them go over the edge in Face, only to hover and move around in circles until they stop. At which point, the fall until they start moving again. The falling down part is probably the native physics taking hold. Anyways, I'll need to work on that part before I do anything else really. I'm also required to work on and finish the weapon firing code. Its basically just a mess of test code that allows the bots to fire through walls and what not. I suppose I'll just make a nice list to keep me on track:
- Implement Z-Axis movement. (I.E. Getting the bot to fall when it needs to fall...)
- Create actual weapon firing code.
- Get RotationSmoothing to be randomized within a Min and Max value. (To make aiming more realistic-ish)
- Implement some jumping action so the bot can have fun.
- Implement some sort of "ignore player until it makes me angry" random logic. So that the bot doesn't appear to only aim for the players all the time. Current the bot will just aim at you all the time and move toward you and shoot you. This behavior has "...got to go!"
- Implement some dodging.
- Re-implement squad tactics and objectives seeking etc.
- Tweak. Tweak. Then more Tweaking.
I'm beginning to wonder if the ideas I have for making the bot seem more real are going backfire on me. If the aiming setup I have now makes the bot Aim with fairly good accuracy then I'm probably going to have to through in some random directions to face every once in awhile and randomize the aiming restrictions a bit more.
Edit: And I forget to add the fact that I need to put in some aiming code for the Z-Axis too. Currently the bot can only aim and fire along one plane, that being the X+Y plane.
Saturday, September 08, 07
After thinking about interfacing the weapons from UT into my AI, I decided that it would be best to just have it simulate an InstaGib shock rifle, as thats my favorite weapon and gameplay. I've come to a blockade though. I've always assumed that what drove a Pawn to move in direction A was simply something like this: Velocity = vector(Rotation) * GroundSpeed. In reality, it seems much more complex than that. My AI's walking speed was set to something like 100. Realizing the great differences between my (well, my pawns) ability to walk, and its ability to walk, I decided to make the basic movement values the same. So, the AI and the Pawn have walking speeds of 440. Well, my happiness came to a crashing halt. My AI moved 10x faster than I did. After looking into both Controller classes and Pawn classes, and after experimenting with what I saw, I can safely say that I have no idea how Pawns get their movement done. Why couldn't they have just done the previously shown code? I had a great remembrance that the Pawns have Karma Physics working with them. I thought perhaps this created friction so instead of going 100 miles an our, it slowed them down considerably. I was wrong, it seems. I think I'm in for another month of trying to work this out, and then have someone come along and give me a solution. Would that be beneficial to me or not? I don't know.
I even subclassed Pawn instead of Actor. What I got was a lot of hellish rotation and zero movement, regardless of how many functions I overwrote.
Wednesday, September 05, 07
Not that much progress at all except for the fact that I've found a decent way to get the AI to use normal weapons without having to make my own. UTRPG has a base weapons class that has a 'Modified Weapon' that it controls. So, if the base weapon were controlling a shock rifle, all of the functions of the shock rifle would be called whenever the appropriate function is called on the base weapon. So function startfire would call startfire on the modified weapon. I suppose I will most likely do it similar to that except I'll have to overide a few things from the controlled weapons for the new aiming system. Hmph.
Sunday, September 02, 07
So I'm sitting here at 3:21 AM. I work at 10:30 AM. Before bed, I decide to take one last look at my code to see if I could find anything that I haven't noticed which would be making things difficult for the aiming code. The AI turned perfectly when doing normal rotations but as soon as it was told to aim at me, it rotated stupidly. I knew it would be something small and hard to notice, but I didn't know until now. I assumed the problem lie in my helper functions which added or subtracted a rotation based on some value. While going about it this way I fixed a few problems with the code that I didn't think about. For example, what happens when my rotational code is passed a negative yaw value. When I first encountered this problem, I just thought a nice small absolute function would fix it. I didn't think about the problems that would have though because the -90 degrees is not the same as +90 degrees so and absolute value would make 270 degrees equal to 90 degrees (which means the rotation from the -Yaw value passed will give a mirrored resulting rotation... -90 degrees = 270 degrees but the AI would rotate to 90 degres). [end incoherent rambling]. I added a little bit to fix that, so that problem resolved, but another problem occured when the AI wasn't rotation in the right direction. I knew it couldn't have been any of the rotational code that decided what way the AI should turn because as I said, when the bot isn't aiming, it rotates just fine.
I like to ramble, sorry... the solution for my aiming problem was quite simple. And, I'll even share it with all of you.
bTurnDirSet = False; //aim code here
I had forgotten that after the AI decides what way it should turn to reach it wanted rotation, I set bTurnDirSet to true so the AI won't keep trying to calculate a new turning direction. Because after every tick the bot tries to aim at the player, bTurnDirSet is always true because unless the bot stops moving, its not set to false so the AI doesn't recalculate its turning direction. Well, now its fixed.
Now the only problem is... interfacing weapons... and moving to a new house soon. Hmph.
Monday, August 27, 07
Not much progress has been made since last update, for various reasons.
1. I have no idea what I'll be doing in the future with regards to my life. I had planned on going to school still and just continuing to work at my current job or get a new job working in an area that I'm more suited for. Neither of those plans are looking to good for me.
2. AI Aiming code. I have all of the neccesary components. The bot is supposed to aim at the player. When the bot has rotated to the rotation with which it will use to fire a shot (hopefully hitting the player, for the AI's sake). The code looks great and is implemented into the movement code. The hitch is, it doesn't work.
Well actually, thats not true. The AI DOES rotate and when its within a certain radius it DOES shoot a beam... but it doesn't rotate or shoot in the direction of the player. I have it set up where the player is always this bots target and when it comes within 1024 UU's of its target it starts to 'aim' at the player. When the player comes within 256 uu's the bot starts firing at the player. When the player is within range of either, the AI goes stupid and instead of rotating properly it decides that its going to take 2 hours to rotate to one direction (often passing that direction). When I implemented this and saw this behavior, I was worried that I had broken my rotational code (again!x5) but I observed that when I went out of the aiming range, the bot started to make its own rotational choices and rotated to said rotations normally. So, I didn't break the rotational code... thats great... the Aiming code however evidently needs to be rebuilt.
3. I'm thinking about how I can get the bots to use the existing weapons in game. The problem you ask? The weapons are basically hardcoded to use Epics class tree and methods. Why is this a problem? Why don't I just remake my own weapons? Are you kidding? Remaking all of the existing weapons would be a horrible decision. This is a fairly simple custom bot and with it, it shouldn't need to use custom weapons that do exactly the same thing as the default weapons. I suppose I could just revert back to my plan for making a mod but I don't like that Idea. I need to somehow make an interface between my bot and the current weapons in UT. That also has its own problems. AimError. Eek.
4. Depression. Depression caused by all of the above and probably more. I'm just really bored and have nothing to do. Its a shame... I waste all of my free time.
Anyways, I'll probably rip out the aiming code and do a rewrite of it (again!) and hopefully by the time I move, it will be working.
Tuesday, August 21, 07
EricBlade expressed an interest in my AI movement code, so here it is. Keep in mind there are probably several optimization that could be made. Also keep in mind that its basically a rip out of my current AI code which also includes other things. As a result the way I have done some things probably isn't very clear. Some function names could be a bit more, clear, but I've commented on parts that I thought I might need to. This is by no means a final version of the movement code. Things will no doubt be taken out, added or changed. If this breaks you, your computer or anyone else, its not my fault. Also Note, my AI class is directly extended from Actor so I wouldn't have to use a lot of Function overrides and deal with a lot of stupid code. If you use this in any code that does extend from another class, you may need to work it in properly. Have fun. Modify it as you see wish but please give Credit Where It Is Due. When the AI is actually done, I will be releasing it as Open Source anyways so don't do anything stupid :D
Update: The following code already got a switch up. I'm now in the process of adding rotational code for 3D rather then the 2D stuff leftover from the mod project I was working on which started this whole AI sharade. Also...
Note: The following code only works with the Yaw component of a rotator. Pitch and Roll are excluded from this. Sorry. Wait till release I suppose.
class DS_AIMovement extends Actor; //Moving System var bool bMoving; //Is the AI moving? var bool bStopped; //True when the AI has stopped and is waiting. var int MovingTime; //The current time left for moving. INTERNAL var int WaitingTime; //The current time left for waiting. INTERNAL var vector LastLocation; //The location the AI was at on the last tick. var bool bWaitTimeSet; var int MinMovingTime; //Minimum value for the movement time. var int MaxMovingTime; //Maximum value for the movement time. var int MinWaitingTime; //Minimum value for the waiting time. var int MaxWaitingTime; //Maximum value for the waiting time. var float WalkingSpeed; //The speed used when the AI is walking... var float CurrentSpeed; //The current movement speed //Rotation System var bool bTurnDirSet; //Has the turn direction been chosen? var int TurnDir; //Direction AI has chosen to turn. 0 - Clockwise 1 - Counter Clockwise var int RotationSmoothing; //How fast does the AI turn var int RotationLimit; //How much difference can there be between the AI's Current rotation //And its Desired rotation var float DesiredYaw, CurrentYaw; //Desired rotation and current rotation /* General Function Section */ function PostBeginPlay() { //Start with random rotation CurrentYaw = rand(65536); SetRotation( SetUpRotator(CurrentYaw) ); MovingTime = Rand(MaxMovingTime - MinMovingTime); MovingTime = MovingTime + MinMovingTime; } function Tick(float DeltaTime) { AINonCombat(DeltaTime); //Handles movement and interactivity with the game world when engaged in combat } /* Movement Function Section */ /* Function AINonCombat Paremeter 1: Type - Float Name - DeltaTime This function gets the movement all set up and going. */ function AINonCombat(float DeltaTime) { //While NOT Moving if( !bMoving ) { //Note: See notes in the Function Description!! AIDecideDirection(); //Deciding Direction To Go In AIStartMove(); //Starting To Move In Decided Direction } //While Moving else { AIPreventBlockedMovement(); //If The AI Is Blocked, We Need To Try And Unblock Him AIDecideTurnDirection(); //Decide Which Way The AI Should Turn To Get To Direction AIStartRotateProcess(); //Start Rotating To Decided Direction if( !bStopped ) AIUpdateMovement(); //Updating Velocity And What Not AIUpdateMovementTimer(); //Updating Movement Timer } } /* Function AIDecideDirection Decides what direction it wants to go on based on its CurrentDirection. I.E. If RotationLimit is 8192 (45 degrees) the bot will have a limit to rotate 45 degrees on either side of its CurrentYaw. So in this case, if the bots CurrentYaw is 90 degrees, it would only be able to rotate to anywhere between 45 degrees and 135 degrees. As an alternative to this system, you can use AIDecideDirectionOLD. There is no restriction of where the AI can go with that function. */ function AIDecideDirection() { local float f; //Decides How Much We Turn local int NYaw; //The angle to add or subtract f = fRand() * 2; //Gives us a float between 0 and 2. NYaw = f * RotationLimit; //Gives us a yaw value between 0 and RotationLimit to add or subtract if( f < 1 ) //We subtract NYaw from CurrentYaw DesiredYaw = OperationWithAngle(CurrentYaw, NYaw, False); else if( f > 1 ) //We add NYaw to CurrentYaw DesiredYaw = OperationWithAngle(CurrentYaw, NYaw, True); else //We do nothing to the CurrentYaw DesiredYaw = CurrentYaw; } /* Function AIDecideDirectionOLD Decides what direction it wants to go on. This new direction could be anywhere between 0 and 65535 (0 to 360). */ function AIDecideDirectionOLD() { DesiredYaw = Rand(65536); } /* Function AIStartMove() This function will get that AI moving in its inital rotation and velocity. It will also start any animations needed. */ function AIStartMove() { CurrentSpeed = WalkingSpeed; SetRotation( SetupRotator( CurrentYaw ) ); Velocity = vector(Rotation) * CurrentSpeed; LoopAnim('WalkF'); bTurnDirSet = False; bMoving = True; } /* Function AIPreventBlockedMovement This tells the AI to stop moving if they're being blocked. TODO: Instead of just stopping the AI, get it to choose another direction to go in. */ function AIPreventBlockedMovement() { //If the pawn has stopped moving and they haven't chosen to stop //i.e. they're being blocked by something. if( !bStopped && (Location == LastLocation) ) { LoopAnim('Idle_Rest'); bTurnDirSet = False; bMoving = False; } } /* Function AIDecideTurnDirection This function, based on the desired direction, determines which way the AI should turn to get to its DesiredYaw faster. For example, if the AI is facing 45 degrees and it wants to face 90 degrees it would be faster to rotate counter-clockwise then to rotate clockwise. Note: A great many thanks goes to everyone who tried to help me figure this part out especially EricBlade from the UWiki who actually figured out the right thing to do. */ function AIDecideTurnDirection() { local rotator A; if( !bTurnDirSet ) { A = Normalize( SetupRotator(CurrentYaw) - SetupRotator(DesiredYaw) ); if( A.Yaw > 0 ) TurnDir = 1; //Counter-Clockwise else TurnDir = 0; //Clockwise bTurnDirSet = True; } } /* Function AIStartRotateProcess This function gets the AI rotating the desired way to the desired direction */ function AIStartRotateProcess() { //If we've set the turning direction and the AI is not standing still if( bTurnDirSet && CurrentYaw != DesiredYaw) { //If TurnDir is 0 (clockwise) if( TurnDir == 0 ) { //If CurrentYaw is greater or equal to 65535 (360) //Then set it to 0 so we can continue if( CurrentYaw >= 65535 ) CurrentYaw = 0; //If CurrentYaw is less than DesiredYaw we need to add to //CurrentYaw to reach the DesiredYaw. if( CurrentYaw < DesiredYaw) //128 is divisible by 8192 (our lowest set yaw value) //Finding the minimum between CurrentYaw + 128 and DesiredYaw. //CurrentYaw + 128 will always be chosen until CurrentYaw equals //or is greater than DesriedYaw. CurrentYaw = FMin( CurrentYaw + 64*RotationSmoothing, DesiredYaw ); else //Here we need to find the max because if we get here //it means that CurrentYaw is greater then Desired yaw but //We still need to add 128 because we're still going clockwise. //For example if we're at 315 (45 degrees in real life) and we want to get //To 45 degrees (315 in real life... remember, the axis' are inverted) then //we would have to keep adding to CurrentYaw until it gets to 65535 (360 degrees) //At which point it will be set to 0 and we can continue adding until we reach the DesiredYaw. CurrentYaw = FMax( CurrentYaw + 64*RotationSmoothing, DesiredYaw ); } else if( TurnDir == 1 ) { //If CurrentYaw is less or equal to 0 then //Set CurrentYaw to 65535 (360) if( CurrentYaw <= 0 ) CurrentYaw = 65535; //If CurrentYaw is less than DesiredYaw and CurrentYaw does not equal Zero -FIX ME if( CurrentYaw < DesiredYaw && CurrentYaw != 0) //We need to find the minimum value between CurrentYaw - 128 and DesiredYaw. //We are going counter-clockwise so CurrentYaw - 128 will always be the min value, //until CurrentYaw is equal or lesser than DesiredYaw. CurrentYaw = FMin( CurrentYaw - 64*RotationSmoothing, DesiredYaw ); else //Here we need to finx the Max between the two values because //We've flipped over 0 and started at 65535 CurrentYaw = FMax( CurrentYaw - 64*RotationSmoothing, DesiredYaw ); } } } /* Function AIUpdateMovement Updates rotation and velocity TODO: Merge with a similar function. */ function AIUpdateMovement() { SetRotation( SetupRotator( CurrentYaw ) ); Velocity = vector(Rotation) * CurrentSpeed; } /* Function AIUpdateMovement This function updates the time the AI has left to move. Also: Decides if there will be a wait time and then updates that as well. */ function AIUpdateMovementTimer() { local int iTempHold; //Decides whether we Wait at the end iTempHold = Rand(5); //If the AI's moving time is over if( MovingTime == 0 ) { bTurnDirSet=False; //We don't know what way we're going to turn so we need to reset that //Since the moving time is 0 we can... START THE ADDITIONAL WAIT! YAY! //Setup for the additional wait if( !bWaitTimeSet ) { AIStopMovement(); WaitingTime = Rand(MaxWaitingTime - MinWaitingTime); WaitingTime = WaitingTime + MinWaitingTime; bWaitTimeSet = True; } if( WaitingTime != 0 ) { WaitingTime--; } if( WaitingTime == 0 ) { //Since the moving time is 0 we can... //If he's not standing still then reset the moving time for the //next move. If the AI IS standing still, then MovingTime will //Use the Waiting Min and Max. Which will be set in the AIStartMove() function. //Finding the max time it will be. MovingTime = Rand(MaxMovingTime - MinMovingTime); //Adding the minimum time to move. MovingTime = MovingTime + MinMovingTime; LastLocation = Location; bWaitTimeSet = False; bMoving = False; //The AI isn't moving anymore. bStopped = False; } } else //If MovingTime isn't 0 then we can keep subracting from it. //It IS a Moving counter after all. MovingTime--; } /* Function AIStopMovement Orders a full stop of the AI. */ function AIStopMovement() { bStopped = True; LoopAnim('Idle_Rest'); Velocity = vect(0,0,0); } /* HELPER FUNCTIONS */ //Helper Function - Returns a rotator with a Yaw simulated function rotator SetupRotator(float Yaw) { local rotator NewRotation; NewRotation.Pitch = 0; NewRotation.Roll = 0; NewRotation.Yaw = Yaw; return NewRotation; } //Helper Function - Returns a rotator with a Yaw, Roll and Pitch simulated function rotator SetupSpecialRotator(float Roll, float Pitch, float Yaw) { local rotator NewRotation; NewRotation.Roll = Roll; NewRotation.Pitch = Pitch; NewRotation.Yaw = Yaw; return NewRotation; } //Helper Function - Returns opposite angle of A function int Add180(int A) { local int NewAngle; A = Abs( A ); NewAngle = 32768 + A; if( NewAngle > 65535 ) NewAngle = NewAngle - 65535; if( NewAngle == 65535 ) NewAngle = 0; else if( NewAngle == 0 ) { NewAngle = 65535; } return NewAngle; } //Helper Function - Keeps Angles within 0 to 65535... function int TrimYaw(int A) { //Using the Bitwise might work, but I haven't //Been able to do this properly with it A = abs( A ); while( A > 65535 ) A = A - 65535; return A; } //Helper Function - Adds or Subtracts Integer B from Integer A // and keeps it within 0 to 65535.. function int OperationWithAngle(int A, int B, bool bAddition) { local int i; if( bAddition ) { i = A + B; i = TrimYaw(i); return i; } i = A - B; if( i < 0 ) i = 65536 - abs(i); return i; } DefaultProperties { // default everything to ThunderCrash.Jakob Mesh=Mesh'ThunderCrash.JakobM' Skins(0)=Texture'DemoPlayerSkins.Jakob_Body' Skins(1)=Texture'DemoPlayerSkins.Jakob_NewHead' DrawType=DT_Mesh Style=STY_Normal bMovable=True Physics=PHYS_Walking bCollideWorld=True bCollideActors=true bBlockActors = True MinMovingTime=2000 MaxMovingTime=2250 MinWaitingTime=500 MaxWaitingTime=2000 WalkingSpeed=100 RotationSmoothing = 1 RotationLimit = 8192 }
Monday, August 20, 07
After trimming up the basic non-combat moving system (of which I trimmed 200+ lines of code if I remember correctly :( ) I tried to re-implement some things that I really wanted. For example, the way I had it setup normally is the bot would move around a bit then stop, then wait, then move around again then stop, then wait, then move around again. I later realized this wasn't the behavior I wanted, especially when I was working on the squad code where the bot would almost catch up with its leader and then stop and wait for 2-3 seconds. I added a couple of checks so that it would no longer do that but after trimming the code up, the movement code broke (again!). So, I've decided to redo it AGAIN but this time build it from the start specifically for the Squad movement (which seems to be a simpler route to take) rather then implementing a broad movement system that relies on a lot of if statements to work in all situations. It also brings my attention to how I have the functions set up. I have a NonCombat function which calls all of the non-combat associated stuff (mostly movement/rotation atm) and a Combat function which deals with all the combat stuff (and which is also an empty function atm). I hate State so I'm not going to touch those (although if I really sit down to use/figure them out they would probably be much more simpler) but I'm wondering if I should just forget the all seperating Combat and Non-Combat and put it all in one big pot. For now, I think I'll proceed with that in mind so I will have the ability to modify the movement code without destroying functionality.
So, now I will just be focussing on rotating the bot, then moving the bot.
I did some reading up on the Interweb about AI techniques and on one page someone was talking about putting weights on to certain things in the game so the AI would have a "hunger" for it more than others. Epic's AI code does this relatively well I suppose. The reason I'm mentioning it is that I think I may at some point put a value on all of the directions so the bot is more inclined to go in one direction than the other. So, within 90 degrees of wherever he's looking the desire to go in that direction will be greater then to turn around and go back. This kind of idea could be adapted to not just movement but to combat as well. If the bot knows theres someone behind him the weight could shift towards that player so the weight would no longer be in a 90 degree field of view in front of him but a 90 degree behind him.
And actually, the more I think about it the more tasty it sounds. This could actually solve the problem of the bot having to know exactly where the player is. If a player was behind a bot and the bot was aware of this, the bot would spin around and start shooting. Us human players (or at least those of us without aimbots...) have to do vector/angle calculations in our head (really, we do!) so we can aim and fire at our opponent and hopefully if our hand/eye coordination is good (and the computer/server isn't lagging) then we would hit our opponent. However, we SEE the opponent, we KNOW where he is, but we only know a rough estimation. We don't know the exact vector of our opponents. Epics bots, well, I'd hate to being them down, but they're aimbotting smacktards. They pretty much know the -exactly- location of all of their opponents. The only reason why, as Eric has previously stated, they don't get you 100% of the time is because of the AimError on all the weapons which throws their shots off. This proposed rotational weight system could actually help prevent that... or actually, I guess it would create a new kind of 'aim error' but it would be more believable. When the bot turns around to shoot at the opponent, based on the direction of the player and the bot, it would assign a weight system to its rotation, the height 'weight' being the direction the opponent is most likely to end up being at when the bot fires a shot. This wouldn't be exact though (as humans don't have the exact location either, just guestimations) and so the bot will have to 'home-in' on the direction. I'm going to stop there before I get ahead of myself (again...) I just started thinking about having the bot learn from the opponent and save directions that the opponent will most likely come in to his FOV... but lets not go there.
Sunday, August 19, 07
I've been doing a lot more Squad AI coding. Just little stuff that will probably make a big difference like allowing the bot to "Hold" a particular location or objective such as a flag. These things will probably be controlled partially by the individual AI but will mostly be controlled by the Squad Leader if the bot is in one. Thats part of the system isn't coded up yet though. Instead, I've decided I really can't put off on re-doing the movement code. The first time through I built it for what I need at that particular time, just a bot that picks a direction and goes there and if they A. Stop moving and aren't just standing still then I force them to either:
1. Go in the opposite direction or
2. Stop moving entirely and wait for the next move decision.
Other cases included hitting "NoGoZone" actor collisions which got them to go the opposite direction also. The system the way it works now is... 'decent', but not 'decent' enough for me to be happy with it. There are too many last minute hacks to get the AI to work with the squad code better so the movement code is really 10 main functions + a few squad hacks here and there. Its really messy and the messiness is starting to show. My bots are getting stuck on walls, the rotational code is messing up now. Just like having to reinstall a windows operating system every once in awhile, an AI totally needs a re-boot.
But that can wait until I get some creative juices flowing again.
Thursday, August 16, 07
Due to the fact that I've been so taken with this business of AI coding, I've decided to drop the idea of this third-person mod and stick with just the AI aspect of it. I'm just going to make a GameType that uses my BotAI. It won't be as magnificent as Epics AI code, of course, but thats only because they use the navigation point system so the bot knows exactly where it can go and how to get from point A to point B. My bots basically just feel their way around and if they 'see' anything amazing/wonderful, they mark it down and save it for later. Because of this, I've also decided to drop the restricted movement aspect of it so now the bots are able to go in any direction from 0 to 360 degrees. Of course this requires me to now code up stuff for pitch control/vertical aiming and I'm not sure if that will be extremely hard, or extremely easy.
This new approach would really only be useable in Deathmatch-centered gameplay. Small CTF/DDOM/whatever maps could also be used by the AI but any large scale maps such as CTF-Face3 would be pretty much out of the question unless one joined a squad of bots as the leader and led them to the flag. Although I suppose it could be possible to, instead of using the savedlocation lists in each AI, have a location list used only for Squads. That would probably propose more problems than it would solve though. But right now, the bots can only join squads comprised of themselves.
Its 100x easier to make a bot that knows exactly where he should go, and shoots his opponents with incredible accuracy, and basically just owns, rather than a bot who makes mistakes, actually gets better the longer they play and learns from his opponents. I've been doing with the idea of actually having a navigation list but this list would be generated by the AI itself and saved to an INI most likely. The idea is basically the same as the bots created by various people for Natural-Selection (mod for Half Life). Although, I'm pretty sure the 'waypoint' files used in those systems had to be created manually. The creators of the bots made files for the default maps but any custom maps had to be run without waypoint files/bots wouldn't spawn on custom maps due to no way point files/server admins had to make waypoints themselves. Its that that I want to avoid. IMO, AI's should be able to learn and improve as time goes on. If someone who is new to UT plays a game, they would probably be quite horrible. In fact, people telefrag such players quite often, haha. As time goes on though, and as they rack of game time, their 'skills' eventually improve. They discover shortcuts through maps. They discover ways to get behind the enemy without them knowing. They can distinguish between high risk and low risk opponents. This is what the goal for my AI is. To play, learn, improve. The trick though is to balance giving the bot information that human players don't normally have like the exact position of an enemy player for purposes of aiming. Epic uses a 'faking' system that makes the bot look like they make mistakes, especially with aiming. There is an aimerror variable on each weapon that effects how much they will miss their target. However the higher difficulty you get, the more impossible the bots become and thus, they target, aim, shoot, and kill before you even know whats going on. Unless a human player has an aimbot, and him and his target are extremely skilled, they're both bound to miss a lot. Bots on Godlike, tend not to miss at all. I'm not greatly fond of their aim faking in UT anyways, so I'll probably look for alternative options for faking human characteristics. One thing I don't want at all is Godlike bots.
EricBlade: This sounds spiffy awesome, and I'm glad I could help. Have you actually built a system where it can move around a level completely independently of pathnodes? The Movement functions have a high reliance on a functioning path network, and I'd love to see a version of that in script rather than in native. One sick thing about the bots, is that once you get to INHUMAN or higher, then you can tell that they are pretty much just shooting everything that has a line of sight to them, and hitting it 90%+ of the time. Bullets and rockets come straight out of their butts. With the existing weapon/aim system, if you remove the AimError stuff, you end up with bots with 100% perfect targetting, at least for hit-scan weapons.
MythOpus: They can move around an entire level but not very efficiently. It would most likely take them awhile to get from one side of the map to another and they'd most likely get stuck every once in awhile. This will hopefully be improved somewhat as I flesh out how I'm going to get them from point A to B efficiently. I think having a navigation system of sorts would be fairly required but it wouldn't be a static navigation system that you see in UT. It would be more of a dynamic one where bots can add/remove the specific important destinations at will if they see fit when their skill increases. Also, as I've mentioned, it would be a navigation system designed by them so mappers would only be able to have minor control over it. (Then again if I could find a decent way to get them from point A to B and ignore Object C, D and E without using any nagivation system at all then we'd ALL be better off). It would be like finding a short cut after you've been going the long way around to an enemy base.
As with the existing AI, I've always found the rockets and impossible shots very annoying. And as with most bots, theres always away around it. For example, on FaceClassic once you capture the flag, if you hide up in the tower for a few seconds until the enemy bots start coming inside, you can jump off and make it to your base because they still think you're up in the tower. I hope to find dynamic solutions for such things. Imagine, bots who made mistakes (and then corrected those mistakes after playing with you for a bit). Hmmph.
EDIT: Actually, I remember reading somewhere on methods for avoiding 'collision' which could be used for such a thing as avoiding objects C, D, and E but I would have to mess around with those methods heavilly so they wouldn't require navigation systems.
EricBlade: Considering that I am working with -zombies- of all things, this doesn't sound like a terribly bad behaviour. Any chance you'd be interested in sharing?
MythOpus: Zombies, huh? Well I am releasing this as open source but I could send you the code that you'd need. Its fairly simple code but I could totally post it up here for you. First though I'll have to work it out again. I've recently chewed it up a bit but I'll put the boken pieces back together to get that Zombie behaviour you're looking for. It IS extended from only Actor though so you may need to work in a few things so it doesn't override certain essential things you might want from your extended classes.Monday, August 12, 07
Thanks to EricBlade, my AI (or so it seems) turns the right way 100% of the time now. Now that that works, I need to decide on what I want to work on next. I was toying with the idea of working on squad logic or something for the AI so all of them can stay together relatively well while still doing their own thing. I don't want to get into full-blown combat work yet as I have yet to decide the direction I want to take with it, the majority of that indecision with regards to how the AI will see the player when its supposed to. Because the AI has no access to NavigationPoints at all (Besides the saved locations that it has travelled) I can't just feed it what Nav Point the player is at and fake it seeing the player by checking the distance from the AI. My experiences with Tracing has pretty much thrown that idea out of the window so I'm not quite sure how I'm going to approach that. I suppose I COULD just feed the AI the players location but I agree with a statement made on one of the countless AI sites I've been to. It goes something to this effect... "Artificial Intelligence in games that are in effect omnipresent is something that todays gamers will soon not put up with." So we'll see what happens and we'll see what I start working on next.
Saturday, August 11, 07
I thought I'd make an update on my progress, or rather, lack of. I could have probably gotten the majority of the combat system completed and probably would have even fixed the majority of the movement problems if it weren't for not being able to get the AI to turn the right direction. I've made a few leaps in my logic in solving the problem though. Like instead of checking to see if the CurrentYaw was larger/smaller than the DesiredYaw, I am also checking if the DesiredYaw is lesser or greater than the opposite of (CurrentYaw + 180 degrees) to see what direction I should turn but that in itself gave me some errors. So tonight I just gave up and attempted to solve it in a way that I really didn't want to even consider. I attempted to just use IF statements... a lot of if statements. Eight if statements for every quadrant that the CurrentYaw could be in. In these if statements I put together all of the info I put together about what might work to help me. The result? A broken AI that doesn't even rotate to where its supposed to much less rotate in the right direction. It decides to go 90 degrees? It rotates to 225 degrees instead. It stops at 225 degrees and suddenly it thinks its starting from 135 degrees. All I can say is that I am quite dissapointed with it. So just for fun and for anyone who reads this... I will post the most recent Turn Direction Deciding code as well as a helper function I've used in it. If you want to take a knack at deciding where I went wrong go for it, but please oh please post your fixed code here. And if you can condense it, please go ahead and do that too :) I'm sorry if I didn't comment it as much as I should have.
Also, just fyi, the "rotation graph" is inverted horizontally from what you would think. I.E. 90 degrees is on the bottom not the top and 270 degrees is at the top so to get from 0 degrees to 90 degrees you would go clockwise not counter-clockwise.
This also means that Q1 is not in the top-right of a graph but at the bottom right.
//This function decides what would be the best way to turn //I.E. if you are at 90 degrees and want to move to 300 degrees, //you don't want to rotate through 180 and 270 degrees just to get there. //You would want to rotate clockwise. function AIDecideTurnDirection() { //TurnDir = 0 is clockwise. //TurnDir = 1 is counterclockwise. //TurnDir = -1 means that the AI won't turn. //Yes... yes... I know how this could change but that will be done when I get this working >_> if( !bStandingStill && !bTurnDirSet ) //You don't need to pay attention to this :) { //Q1 = 0 to 16384 (0 to 90 degrees) if( CurrentYaw >= 0 && CurrentYaw <= 16384 ) { if( DesiredYaw >= 0 && DesiredYaw <= 16384 ) //Same Quadrant As CurrentYaw { if( DesiredYaw > CurrentYaw ) TurnDir = 0; else if( DesiredYaw < CurrentYaw ) TurnDir = 1; } else if( DesiredYaw < Add180(CurrentYaw) && DesiredYaw > 16384 ) { TurnDir = 0; } else if( DesiredYaw > Add180(CurrentYaw) && DesiredYaw <= 65536 ) { TurnDir = 1; } else TurnDir = Rand(1); } //Q2 = 16384 to 32768 (90 to 180) if( CurrentYaw >= 16384 && CurrentYaw <= 32768 ) { if( DesiredYaw >= 0 && DesiredYaw < 16384 ) { TurnDir = 1; } else if( DesiredYaw >= 16384 && CurrentYaw <= 32768 ) { if( DesiredYaw > CurrentYaw ) TurnDir = 0; else if( DesiredYaw < CurrentYaw ) TurnDir = 1; } else if( DesiredYaw < Add180(CurrentYaw) && DesiredYaw > 32768 ) { TurnDir = 0; } else if( DesiredYaw > Add180(CurrentYaw) && DesiredYaw <= 65536 ) { TurnDir = 1; } else TurnDir = Rand(1); } //Q3 = 32768 to 49152 (180 to 270) if( CurrentYaw >= 32768 && CurrentYaw <= 49152 ) { if( DesiredYaw >= 32768 && DesiredYaw <= 49152 ) { if( DesiredYaw > CurrentYaw ) TurnDir = 0; else if( DesiredYaw < CurrentYaw ) TurnDir = 1; } else if( DesiredYaw > Add180(CurrentYaw) && DesiredYaw < 32768 ) { TurnDir = 1; } else if( DesiredYaw < Add180(CurrentYaw) && DesiredYaw >= 0 ) { TurnDir = 0; } else if( DesiredYaw > 49152 && DesiredYaw <= 65536 ) { TurnDir = 0; } else TurnDir = Rand(1); } //Q4 = 49152 to 65536 (270 to 360) if( CurrentYaw >= 49152 && CurrentYaw <= 65536 ) { if( DesiredYaw >= 49152 && DesiredYaw <= 65536 ) { if( DesiredYaw > CurrentYaw ) TurnDir = 0; else if( DesiredYaw < CurrentYaw ) TurnDir = 1; } else if( DesiredYaw < Add180(CurrentYaw) && DesiredYaw >= 0 ) { TurnDir = 0; } else if( DesiredYaw > Add180(CurrentYaw) && DesiredYaw < 49152 ) { TurnDir = 1; } else TurnDir = Rand(1); } else if( DesiredYaw == Add180(CurrentYaw) ) TurnDir = Rand(1); if( DesiredYaw == CurrentYaw) TurnDir = -1; bTurnDirSet = True; //We don't need to set the turning direction anymore next tick } } //This takes a UU Degree and adds 180 degrees to it //And returns a new angle to use function int Add180(int A) { local int NewAngle; NewAngle = 32768 + A; if( NewAngle > 65536 ) //We want to be within 0 to 360 degrees NewAngle = NewAngle - 65536; if( NewAngle == 65536 ) NewAngle = 0; else if( NewAngle == 0 ) { NewAngle = 65536; } return NewAngle; }
EricBlade: I suppose it might be worth noting that 65536 == -1, so 0 and 65535 should be equivalent. It seems that if you Normalize() your rotators, then you should be able to just figure out which is closer to 0, and that would give you the direction to go .. or am I misunderstanding?
~~ Unreal rotations are modulo 65536, so 65536 == 0 and 65535 == -1. Or, to put it another way: if (RotationValue 1 & 0xffff) == RotationValue2 & 0xffff) then both are the same. 0xffff in decimal is 65535 and (x & 0xffff) is the same as (x % 65536). Note however that Normalize() results in values between -32768 and +32767.
EricBlade: I think I've stated before that my math skills are a bit rusty and lacking, so I'll need to study that for a bit to figure out how that works. Still, if you Normalize the CurrentRotation and the DesiredRotation, then it seems like you could subtract the DesiredYaw from the CurrentYaw, and if your result is positive, you go one way, and if negative, you go the other?
MythOpus: I was aware that when talking about bytes it will only go up to 65535 but does that mean I should actually only use the rotations from 0 to 65535 or is it okay if I use 65536? As far as Normalizing CurrentRotation and DesiredRotation and then subtracting DesiredYaw from CurrentYaw, I have code written up for that but theres something wrong with the code that actually rotates the bot around. I wish I would have saved more backups. I will have to fix whatever problem its having first before I can actually test your code though. Thanks for the help so far and by all means, if after studying it for a bit you realize something, do share :)
EDIT: I just fixed (or so it appears) the rotational code of the AI. It seems I forget to tell it to stop rotating in DirectionX even after it reaches its DesiredYaw. I don't know how I didn't notice that. Anyways, I tested your suggestions (65536 now is 65535, And your sugg. on how to get the proper rotation) and it seems to be the closest thing to perfect compared to all the other bits of code I've tried. However, the code appears to have problems when the DesiredYaw is 45 degrees less than the CurrentYaw and when the small angle between the DesiredYaw and the CurrentYaw are approx. 135 degrees. I.E. If rotating clockwise will have you moving at an angle of 135 degrees, it would decide to move counter clockwise. Any ideas as to why?
function AIDecideTurnDirection() { local rotator A; if( !bStandingStill && !bTurnDirSet ) //If the AI has not chosen to stop moving and if the turn dir isn't set... { A = Normalize(SetupRotator(CurrentYaw)) - Normalize(SetupRotator(DesiredYaw)); if( A.Yaw > 0 ) TurnDir = 1; //Note: Currently when A.Yaw is 180 degrees it will just turn clockwise rather than randomize between //CW and CCW else TurnDir = 0; bTurnDirSet = True; //Hack so it doesn't keep trying to determine turning direction } }
SetupRotator just takes an integer and returns a rotation with a Roll and Pitch of 0 and Yaw of that integer. And on second thought... I might try Normalize( SetupRotator(CurrentYaw) - SetupRotator(DesiredYaw) ) and see where that gets me...
Edit 2: EricBlade, you get... A delicious batch of...E-Cookies. The AI now rotates in the proper direction! Thank you so very much.
function AIDecideTurnDirection() { local rotator A; A = Normalize( SetupRotator(CurrentYaw) - SetupRotator(DesiredYaw) ); if( A.Yaw > 0 ) TurnDir = 1; else TurnDir = 0; }
Monday, July 23, 07
I've cleaned/fixed up my AI class. My gameplan now is a few things. Firstly, I need to tweak/fix some more of the AI. Its moving fine but I want it to move more realisticaly. If I were some sort of soldier, I wouldn't walk around all the time and I wouldn't be turning around really fast/a lot. So, I will be tweaking the rotate smooth settings and definitely also need to get it to stop moving around too much. Next on the agenda will be to get some sort of Combat system up and running for the AI. I've already started a bit on what will move me in to the actual combat system. Right now it keeps a list of the spots where its movement ends and will keep track of what directions can't be moved in at that spot. I.E. If the AI is at the top right of the map in a corner, it has to know that it can't move up and can't move any further to the right as it will be blocked by a wall. The AI will then use these locations when in combat to decide good places to go based on where they've seen the player. This system should work fine in small spaces, which will probably be the majority of the mod, but if the AI encounters larger areas it will take quite awhile for it to map out a good understanding of where it could go. I could probably just incorporate scripting such as defense points and what not but I don't want to shy too far away of letting the AI figure things out on its own and doing fairly well at it. After I have a basic combat system up and running, I will probably re-code my player controller to incorporate things like rotate smoothing and other gems. I also need to stop movement when it is against the wall moving at a 45 degree angle to the wall as this will mess up any Combat location things I want to implement. Also, I really, really, really need to get the wall strafing fixed on the player controller. It will still wall strafe off walls and what not, something I don't want the player to do.
Saturday, July 14, 07
Just a small update. I finally have the bot rotating properly as it moves. It doesn't -always- turn the way that would take the less time to get to its desired angle, or so it seems but it is good enough for me atm. The next step is to optimize and clean the big mess of code I have been spending my time making. Then I can see if the bot is actually rotating wrong sometimes (which is really hardly noticeable) and then its on to some more movement stuff. Yay.
Tuesday, July 10, 07
I was about to start work on the AI's combat system but I decided it would be best if I would continue on the navigation system. I added a few tweaks here and there, mainly seperating the normal moving time and waiting time. This means when the bot is moving around they will have a minimum and maximum time to move. If the bot chooses to sit in one spot, they will have a seperate minimum and maximum duration for waiting. This kind of helps out by stopping the bot a bit. Currently, it keeps moving around really awkwardly. I plan to implement another set of min and max durations for the wait time before picking a different direction to move in. I also implemented a movement smoothing system for the AI (and I'm not sure if I'll implement it for the player) so the bot doesn't make sudden and drastic rotational changes. The problem right now with it though is that A. The bot gets stuck on walls sometimes and B. Because some angles are the same as others ( i.e 360 degrees is the same as 0 degrees ) the bot will only turn one way (his right) when changing rotations. This happens as his velocity is being set so as they're moving they rotate to where they want to look. It moves a bit slow right now but after I fix the few glitches it has, I will tweak the rotation rate etc. Right now, I could just rename the class to Zoolander and no one would be the wiser though. I hate dealing with angles. Now its time to work out a simple and neat progmatical (is that a word?) to have it decide if the direction is closer to his left or right and then start rotating accordingly.
Saturday, July 07, 07
Remember that 'gameplan' I was talking about last entry and remember how I didn't finish it? I probably won't. The point of it was more of a little something to keep me focused anyways. The reason for me not finishing it is the same reason I will use for the fact that there has been pretty much 0 work done on the mod: Humidity + Heat = Dalin being very stressed/unable to focus/irritable. This week/next week is full of work too so there is not much I will be able to do even when it does cool down a bit. Its good though. This humidity gives me a reason to clean my room and do other things like play my DS >_>
Thursday, July 05, 07
The Gameplan
I've been thinking about outlining my plans for the Enemy AI for awhile so her it goes. The AI will be pretty simple. The design goal is to create autonomous (or at least semi-autonomous) enemies that won't rely on NavigationPints or access to player info to be decently effective. The enemy will walk and interact with the world on its own and will require no instruction from the map maker on what to do while still be able to scripted actions if the mapper requires special events to be triggered. I will now seperate and talk about enemy movement and enemy interactions individually.
Enemy Movement
In UT2004 and most other games based on the UnrealEngine, enemy AI needs NavigationPoints to move around a given map. Without these NavigationPoints, the enemy will either stay in one spot or move around aimlessly. They will do this until the player comes into their general viscinity at which point they will shoot at the player and try to follow them. This usually ends up with them getting stuck or finding their way back to the spot where they started from. My goal with the movement is to use a similar idea but get rid of the idea of NavigationPoints altogether. The AI will be able to understand, even if only having a vague notion, of what their surrounding environment is.
Since there will only be 8 directions availabe to move in, the AI will walk around their surrounding area. The AI will mark down significant locations such as decent cover positions and the perimeter of the room that they are in. When the player encroaches onto their position and is heard or seen, the enemy will react either by attacking right away or finding cover. The enemy bot will not have any knowledge about the player other then what he hears/sees and if moving towards the players position, the player may have moved away undetected at which point the enemy will appear confused and attempt to locate the player again. Using the perimiter locations as guide, the AI may use this information in an attempt to flank the player.
The AI will still be scriptable but as soon as the script has completed the normal workings of the AI will kick in and the enemy player will move around his environment and watching for the player.
Enemy Interactions
Generally speaking, the AI knows everything about the player. Where they are, how much health they have, armor, what weapon they are currently using etc. This gives the AI a one-up on the player. My goal is to eliminate this by forcing the AI to get information for themselves. They will only know what they see/hear and assume. For example, if they see the player come into the room with a slow firing weapon and see him duck behind a crate, they may decide to rush him. However, what they didn't know is that the player switched weapons to a faster weapon and moved into the shadows. Firstly, because the players info isn't available to the AI, they won't be updated on perhaps the best tactics they should use again him or even where he went. Secondly, they might not be able to find him because if the player is in the shadows, the chance that the enemy AI will see him is drastically reduced (he will be a NINJA after all) and so he would be able to attack the AI from behind with a sneak attack or avoiding them altogether and continuing on.
When a bot finds the player, he will alert his squad and then execute whatever tactics he deems neccesary.
WIP
Tuesday, July 03, 07
I decided to move my focus from the player movement system to building what will be the enemy soldiers/aliens/whatever that the player will be up against. I started with the movement system after I got the barebones of the enemy done up, which was basically just a few default varibles to be set. My enemy bot class isn't sub-classed off of Controller because I didn't want a whole bunch of useless variables and functions that I would either not use or have to override. I may decide to do this with the actual player class itself but I haven't decided if it will be worth the trouble.
The movement system of the enemy is pretty simple actually. Much more simpler then that of the players movement which required capturing of inputs and yadda-yadda-yadda. I tried a more complex approach to the AI and got a 'Global' list of navigation points in the GameInfo and made a few functions for the AI to call. When the AI was going to make a move it would call a function in the GameInfo that would create a list of nearby NavigationPoints and decide (randomly) on what point it would tell the AI to move to. I had a few issues with this that related back to when I was trying to implement mouse-click movement of the player, where the player would sometimes go to where you wanted it to but sometimes it would just keep walking past where you clicked. Some pondering about this led me to the conclusion that dealing with it wouldn't be worth my time as even if I did get it to work, I would still have to deal with the fact that the bot would have to move to far away targets and deal with obstacles and what not. This was not high up on my list of things I would absolutely enjoy doing.
I then came to the conclusion that it would just be a lot simpler and easier to copy the system I'm using for my player's movevments and simulate the inputs. So I set up a tick function that will randomize between 8 integers.
Integer | Direction |
0 | Up |
1 | Down |
2 | Left |
3 | Right |
4 | Up + Left |
5 | Up + Right |
6 | Down + Left |
7 | Down + Right |
8 | No Movement |
After it decided what direction it would take, I set the rotation to the corresponding direction and the velocity to whatever the default walking speed will be, which is for the purposes of testing, 100. This gets the bot moving (as the walking animation loops) and as it walks several things happen. When it first starts to walk, a counter is set to a random value between a minimum and maximum move time. Then every tick, the counter is decreased until it is 0 at which point a new direction is decided and it starts all over again.
There are some other tid-bits of code involved as well though, for example, a 'small' array that saves the last two directions the bot has moved in. This array is used in an attempt to stop the bot from moving in the same direction over and over again. When a direction is chosen, it is checked against the array to see if the direction should be changed. If the direction is the same as the direction chosen two direction-changes ago, then it should randomize again. This new direction is not saved to the array. We then check to see if the new direction is the same as the direction used prior to the last direction change and if it is, we randomize yet again. If it is still the same as any old direction in the array then we decide that there's nothing we can do and instead we decrease the max time the bot will be moving in that chosen direction. Not the most elegeant way of handling such a thing but it gets the job done for me.
There is much more work to be done though and I think implementing a combat system will be much more easier then my dealings with the player controller.
Note: If you know of a better way to stop a randomized number from being chosen again, please let me know...
Friday, June 29, 07
Don't you just LOVE it when the code assigns random values to important variables? I do. After taking a day off from even looking at my code, I loaded up UT to see where I was with it. Apparently, I still haven't fixed the 'wall strafe off the wall and continue wall strafing' issue, something I really need to look at. I found yet another bug in my current iteration of the wall hugging code too. If you wall strafe into the corner then get out of wall strafe mode, then get back in it on the other wall on the other side of the corner, you'll end up with accelerations of -84 in both X and Y axis', and you'll be stuck in wall strafing mode. This convieniently glues you into place. As of right now I have absolutely no idea why this is happening as '84' isn't a value I use anywhere in my code and the acceleration can only be set to 1 of 3 values which are '270' when walking, '500' when running and '120' when wall hugging. I suspect the fact that I haven't 'caught' any cases where the player might try to wall strafe on a diagonal wall might be the cause of the bug, but why it would set my accelerations to -84 is beyond me.
Graphik: I like it even better when people assume that computers do random things for no reason. ;)
MythOpus: But Graphik, it DOES have a reason. To annoy me. Remember HAL 2000? My computer is HAL GOBLIN 2000. I stopped it from freezing the player in place but the accleration ends up being 84 all the time still. Now it just won't make a big difference as the player isn't moving anyways.
Wednesday, June 27, 2007
Happy Birthday to me.
I decided to take another crack at the wall hugging mode and I finaly got it to work. At least for the most part. Now I have to add some checks to not let the player wall hug if they are going at wall diagonally and I also have to figure out some way to stop the play from wall strafing on walls that don't exist. Currently when a player enters wall hug strafing mode, say, on a pillar of some sort, they will hug the pillar with their back and they will be able to strafe to either side of them and then also move forward (which will take them out of wall strafing mode). This happens wonderfully when a player goes straight into something however if they strafe off the pillar they will keep wall hugging against thin air. To fix this I could do several things, one being force the player to rotate around the pillar or around the wall or whatever but an easier approach would just to add a few checks here and there to determine if the player can move in the opposite direction that they want to rather than being stopped by a wall or other object. I'll think on the subject for a bit.
I also got a laptop for my graduation and birthday so I can get some coding done while at the local cafe. Yippee!
Update: I think I've decided on a solution for my issues. Currently, the wall hugging system requires a player to walk up to a wall and then try and walk into it. At this point, the player will turn around and the player will be locked into wall hug strafing mode. This means that the player will only be able to strafe across the wall or move away from the wall, which will get them out of wall hugging mode. This also means that currently, if they try to go in the direction of the wall again, nothing will happen. This also means however that if the player strafes off a wall, they would strafe into an open hallway and will be hugging against thin air. To solve this issue I've decided that it might be worth to implement a double key wall hugging system sort of like what is implemented in the Metal Gear Solid series. To hug against the wall in those games you must hold down the key that is in the direction of the wall... for example, if the wall was below your player, you would have to hit the down key until you hit the wall and enter wall hugging mode at which point to remain in wall hugging mode you must hold down the down key and to strafe you would use the left/right keys as per normal. I don't forsee this to be a giant issue as all I will probably have to do is change a few lines of code around.
Monday, June 25, 2007
I graduate today. Anyways, there hasn't been much working on the mod project as I've been messing around a bit with a Shell for Windows called LiteStep. Its neat. I did however manage to fix, then break, then fix my movement code. I will add that its been about the 10th time where I have had to do this. Whether it is due to my own incompetance or not I will never know. I was messing with the Wall Hugging code and then right out of nowhere, the movement code changes on me and I'm not in any direction I'm supposed to. After this I took out all of the Wall Hugging code and the movement system seemed to work fine for a short while. Then I noticed that some debug code that I have was reporting the wrong direction that the player was moving in. After investigation, it seemed that either I mistakingly changed some Yaw settings or The Goblin decided it would be funny to flip the Y-Axis on me. Oh the life of an amateur UnrealScripter. So I went through all of my calculations and tried to make sense of the mess. The result is this table.
Basic Movement | |||
Calculation Used | Calculation Value | Corresponding Degree | Direction |
16384*1 | 16384 | 90 | DOWN |
16384*2 | 32768 | 180 | LEFT |
16384*3 | 49152 | 270 | UP |
16384*4 | 65536 | 360 | RIGHT |
Diagonal Movement | |||
Calculation Used | Calculation Value | Corresponding Degree | Direction |
16384*2 - 16384/2 | 24576 | 45 | DOWN+RIGHT |
16384*4 + 16384/2 | 73728 | 135 | DOWN+LEFT |
16384*2 + 16384/2 | 40960 | 225 | UP+LEFT |
16384*4 - 16384/2 | 57344 | 315 | UP+RIGHT |
So all the angles are negative angles (found clockwise from 0) which makes life very interesting and I can only imagine the newer problems I'll be facing when I decide to start coding the Wall Hugging system again. Right now I'm going to focus on backing up and documenting the code I have in case I screw up.
Wednesday, June 20, 2007
I've decided on a general theme for this thing. I've thrown aside magic and monster creatures trying to destroy the world with evil powers in favor of a less common approach. NINJAS! I'm just hoping it won't be over the top lame ninjas, so I'll try extra hard to make it 'cool'.
With this decision made I've had to make a few changes to the code, which started with placeholders. Ninjas don't need magic or magic experience levels or spells... they've got uber skill and knives. I also started to fiddle with the movement system once more even though go it to work the way I wanted it to. I tried adding a wall strafing system. In theory, it would work like this...
The player walks up to a wall. If the player walks into the wall, the players character will lean its back against the wall and you can then move (slowly) against the wall in a similar fashion to the Metal Gear series. This tactic would be useful for getting past heavilly armed guards when there is very little light and could be used as a scare tactic on guards in rooms with pillars every where. Anyways, here is how those changes went.
BOOM!
They didn't work.
I don't quite understand why I'm having so many problems. I'm pretty sure I understand the vector and rotator business so that hopefully isn't the issue. I started to test some things out before I worked heavilly on getting it to work the way I want it to. This required me to strip/trim the existing movement code up a bit so now instead of just setting the rotation of the pawn, I am also setting a custom enum. So when the player is moving forward, the enum will tell you that its moving forward etc. This wasn't the difficult part.
However, then I started to test World Collision things though. I thought that the HitWall event might help me determine if the Pawn is hitting a wall (at which point the wall grab will occur) but this didn't work at all.
Then I attempted to use a FastTrace (albeit with some theoretical variables that I was guessing would work) and that gave extremely odd results. In my test map, I have a room of pillars (just rectangles that reach from top to bottom of the room) and the FastTrace would only show a collision with the left and front of -some- pillars. After fiddling with this to no avail, I tried an actual trace which gave similar results. Also, when the pawn would collide, I had a little piece of code that added 180 degrees to the direction of the pawn (for the huddle against the wall) and this only inverted my movement keys similarly to the problems I was having before with the movement system.
Dalin, is not a happy programmer right now and he has a Calculus Final tomorrow morning. At least the UE Goblin won't be able to ruin that for me.
Edit: I got the player to 'hug' the wall, minus the animation of course. That will come when most of the code is done. Getting the player to move along the wall has proved much more difficult though. When the player enters the 'wall hug' mode, I've tried different ways to isolate the directions of movement but nothing works so far the way I want it to. I can get the player to run up to a wall and then turn around and 'hug' it, but then in that state I only want the player to be able to move forward which will get him to stop hugging the wall, or be able to move across the surface of the wall while still looking in the forward direction. I.E. The player will strafe across the wall. This has proved hard to implement then I realized. For one, I can't seem to lock the player into the 'wall hug' state properly, and for two, I can't seem to get the player to move across the wall without screwing up my movement axis'. Hopefully doing a semi-rewrite will help me work the kinks out.
Ambershee: You could try creating volumes over walls, and when the player enters them, press up against them, rather than trying to detect walls themselves?
MythOpus: While a good idea, I don't want the mapper to have to do a lot of extra things to make the mod work as needed. I did thinkof a solution though... while early in the morning of course. I am going to check the location of the pawns location against the location of the pawn a second or so prior. If they are the same then I will work some magic and get the player to look like he's hugging the wall.
Ambershee:A viable solution, I guess. However what happens if the level designer wants to prevent a player from being able to hug certain walls or surfaces, or a certain wall or surface isn't a brush, but perhaps a mesh or something?
MythOpus:Well to answer you question about what happens if its not a brush... the system will work the same way. I didn't really explain it well before but here's what I've done. When a player moves somewhere, their rotation changes as well as their acceleration. They accelerate in the direction that they're facing. Because the acceleration of an object can be greater than 0 while the velocity of that object can remain 0, i.e. the object is being stopped by something, I can do the following.
if( ( ( Pawn.Acceleration.X > 1 ) || ( Pawn.Acceleration.Y > 1 ) || ( Pawn.Acceleration.X < 1 ) || ( Pawn.Acceleration.Y < 1 )) && ( Pawn.Location == OldLocation ) ) { //Do wall hugging stuff here }
OldLocation is basically just the previous location of the player when he last tried to move. First we check to see if the player is trying to move in any direction (except for the Z direction because this is a top down rpg and you don't really need to wall hug while falling or jumping) and if thats true then we check to see if the players new location is the same as their previous location, that is to say their velocity is 0. This means for the most part that the player is trying to move but can't, so we can assume that they are trying to move against a wall or pillar, or some other brush or mesh. That won't be the case all of the time of course but you can add/minus stuff to solve any problems.
Note: The check to see if there is any acceleration taking place could probably do with some changing but I didn't know how to check to see if there was any acceleration in any direction otherwise.
To answer you question about the mapper not wanting to allow the player to hug the wall, I'm sure I could use the volume idea as I don't believe there would be any maps where the player wouldn't be able to do this. The only situation where I can see this would be needed is if the mapper had a large vat of boiling lava and didn't want the player getting burnt though. Other than a volume, a trace to a walls surface to get the texture or to a mesh could be used. The information we would get would be checked in some list of 'textures and meshes that you cannot wall hug on' that would be supplied by an in map 'info' actor where the mapper could specify I suppose.
Tuesday, June 12, 2007
I haven't really added anything lately. I just implemented a diagonal movement system... nothing major or awe inspiring. I still haven't come up with a concept for this yet though. A techy-ish RPG would probably be the easiest to pull off but I don't want this to become a horrible clone of Alien Swarm. I've prettied up my test map and added an elevator/transit train to test out how my camera settings would react to the player changing z-axis location. I think it should be fine as long as the camera stays within the boundaries of the map. I don't want it to be doing stupid things like not rendering certain objects. Thats pretty much it for now.
Saturday, June 09, 2007
I decided I had enough with the mouse problems. My fault. I thought using some 'open source' mousing code would be easilly made to work. Its either a problem with the way I coded it, or as its suggested, not meant to be used with UT2004 as it was written for an engine pre-UT2004 and the measurements and values used may be vastly different. And so, what we have here is a mouse that won't move properly.
Its not all bad news though. I decided to revert back to my old plan of forcing the player to only move in one of four directs, them being up, down, left, right. The reasons I avoided this was because of bugs in the code and I believed to make the bugs go away, I would have to overite the PlayerWalking state, and I despise states.
However, I had to overwrite the player walking state for the mouse code so I thought why not. The overriding is working but not without its problems. The pawn, for some reason or another keeps reverting back its starting rotation (360 or 0 degrees) and I've been trying to track down why unsuccesfully. I will have to burn some code to find out the source of my problems I fear.
Update: Victory. The problem with the movement code was my fault. Problem with the logic to be precise. I check for any movement on the x or y axis and if there isn't, I don't change the rotation. The problem was that the Acceleration of the player was being decided outside of the if statement 'family' and when it converted the Rotator to the Vector and multiplied it by the players ground speed, it will give a vector with an actual value (because rotator conversions to vectors give a vector with a length of 1 or something to that effect) and then the new acceleration was passed off to some other functions to be used with. Long story short, problem fixed and now its just about getting a hud, new enemy interaction code, a new weapons set ala Zelda, levels, art erm... actually.. I may have a while to go.
Wednesday, June 06, 2007
I officially hate vectors. At every example I've seen, getting the distance from one vector to another to done with:
VSize(VectorA - VectorB); //or VSize(VectorB - VectorA);
I want to use VSize as for some reason my players location will never equal the location I want it to move to so I have to make it move as close as possible to that location. Two things aren't happening the way I thought they would.
- It seems to be calculating the length of the vector from the origin. From what I remember from Physics, that can lead to complications.
- The 'distance' from Pawn.Location to TargetLocation (where the player wants to go) is never usually less than 256 even if the pawn is right on that spot.
If I don't get an answer to this soon I'm going to move to a less desireable but a million times less stressful solution. I will place an invisible actor where the player wants to go, get the pawn to go in that general direction at whatever speed and when it collides with the invisible actors collion radius, it will stop the pawn. I'm not exactly thrilled about this method though, and it may complicate things if I decide I want to make it a massively multiplayer online roleplaying game, instead of just a roleplaying game.
Edit: I did a quick implementation of the above idea, to spawn an actor that will stop the pawn when it gets into its collision radius. I extended it from Actor and forgot to set bHidden to true, and I've learnt something quite odd because of it. The reason why VSize appears to be being calculated from the Origin of the Level is because the TargetLocation is being set wrong... This, is going to be fun.
Saturday, June 02, 2007
I've recently decided that movement keys are the stupidest things ever... So I'm not going to have them anymore. Instead, the game I'm working on will be almost entirely mouse driven. This for some reason seems to make my job of even getting the basic movement system done that much more complicated. What I have now (that isn't working) is fairly straight forward. Player clicks the mouse somewhere on the map, the players 'avatar' will move to that position and stuff. Whats happening now is that the avatar will move towards the place where the player clicked the mouse, but it will just keep walking. I'm going to have to look at some AI code to figure this out I think.
Friday, June 01, 2007
I've recently decided to pick up UnrealScript again after a very long absence of anything programming/scripting related (excluding php). I hoped to refresh my memory on everything UnrealScript in time for the roll out of UT07 (not that I think its going to be worth buying)... and I've already made some forrays into game design that I couldn't do before. The first of these is mouse/cursor support. Thanks to the Mouse Code from UDN I now have a lovely mouse in game, and with a few lovely changes here and there, I have a player finally following the mouse.
This was not without its challenges though. Right now the design idea for this gametype I'm working on is that of an RPG, a top-down perspective one much like Zelda (the originals ie. super nintendo, game boy etc.). I attempted first to lock the rotation of the Players view which was pretty simple. To do this I created a custom Player Controller and overrided the CalcFirstPersonView and CalcBehindView functions. Something like this:
function CalcFirstPersonView( out vector CameraLocation, out rotator CameraRotation ) { CameraLocation.Z = Pawn.Location.Z + 640; //Get the player view above the player CameraRotation.Pitch = -16384; //Pitch the camera downward CameraRotation.Yaw=-16384; //This WAS set to 0 but it was changed... you'll hear about that later Pawn.bOwnerNoSee = False; //In First Person View, players can't see their own pawn for various reasons but that doesn't //matter anymore if(Pawn.Weapon != None) //An ungraceful way of dealing with the first person weapon model... I couldn't get it to 'hide' so,... DESTROY Pawn.Weapon.Destroy(); }
This worked... for awhile. Until I realized an error on my part. After this I started work on the actual movement of the pawn. It... was stressful. I looked at the UpdateRotation function as it was suggested that it would be a good place to override player input. I used code simlilar to the following to catch the input and change the rotation accordingly.
if( aForward > 0) NewRotation.Yaw = SomeValue; else if( aForward < 0) NewRotation.Yaw = TheOppositeOfSomeValue;
There is more to it than that, for example I also checked for any strafing input, but it didn't work the way I wanted it to. In retrospect, it probably would have worked if I would have fixed my Player View problem (that I'll explain later) but the code I have now is much better I think. I wanted the player movement to be fairly simple. "Up" goes up. "Down" goes down. "Strafe Left" or "Left" goes left. "Strafe Right" or "Right" goes right, just like in most Top-down rpgs. But as I said, it didn't quite work out. At first the forward and reverse directions were okay, but then the left and right directions gave the same results as the forward and reverse, ie. Right went down, Left went up. Changing the angle the player would rotate too only further confused me. I gave up on that for awhile and looked at other options for player movement. I finally found some decent mouse code from UDN, plugged it in and messed with it until it worked as I wanted it to. The source code for the mouse in a 3d space only contained the code for the position of the mouse so I had to mess with it until I could convert the location into a rotation succesfully. Even this gave me troubles though. At first I believed it to be a problem with converting a vector to a rotator. While this may have contributed to the fact that the players rotation never matched up with the mouse, it was not the main problem.
The main problem was that my player view's yaw was wrong. I made some lovely images to clarify.
Figure 2 is where it was all wrong. The map I use for testing purpses is a single vertical room not a horizantal room and my player view was set to make it look like it was actually horiztonal. This played havok with my rotation and caused a lot of things. After I fixed this, everything miracoulously fell into place. Anyways...
Currently I have a player that goes forwards and backwards and rotates in the direction of the mouse. This behaviour may change (I may revert to only having 4 directional movement) but it seems to work for now. All I need to figure is how to add strafing into the movement of the player.