Jump to content

Rick

Members
  • Content Count

    7,776
  • Joined

  • Last visited

Community Reputation

1,458 Excellent

2 Followers

About Rick

  • Rank
    Advanced Member
  • Birthday 12/04/1979

Profile Information

  • Gender
    Male
  • Interests
    Family, golf, football, programming, games

Recent Profile Visitors

52,000 profile views
  1. Anytime man. Feel free to ask anything anytime and I'll do my best to answer
  2. Remember this is being called on ALL the monsters. So hurtMonsterPosition is the monster that got hit, but when it fires for the other monsters self.entity is that other monster checking it's position against the one monster that got hit. A good thing you can do is set these values to a variable and System:Print() the value out so you can see what it is and if it's something that you aren't expecting.
  3. So when you're testing this stuff you can put a bunch of System:Print() commands in places to see if it goes into if statements and such. SO place a System:Print("A") inside the if data.hurtMonsterPosition blah blah to see if it goes inside that. If it does then you need to figure out how to set the player as this monsters target. I'm not 100% sure yet how to do it. I assumed it was just setting self.target but maybe not.
  4. OK figured it out. My loop in RaiseEvent() was wrong. Use this RaiseEvent() function and it works: function RaiseEvent(eventName, data) -- if someone tried to raise an event that doesn't have an entry in our events table do nothing if events[eventName] == null then return end -- loop through all the subscriptions for this event (there may be many game entities who want to know about this event) for k, v in pairs(events[eventName]) do System:Print("Raising event "..eventName) local scriptFunc = v.scriptFunction local script = v.scriptObject -- insert the functions into the eventCoroutines table. this will be iterated over in the main game loop below and resumed into table.insert(eventCoroutines, { co = coroutine.create(scriptFunc), args = data, script = script }) end end The difference is the table of callbacks within a function doesn't go from 1 to x like how I was iterating over it. This loop will loop over all sub tables of the event no matter what eventId is there. My bad.
  5. I just use the old animation lua script Josh had because I built this idea into it and working with callbacks in Lua is just easier. Still wish by default this LE PlayAnimation function gave us that capability, or he added a RegisterAnimationEvent() function to link the timing to a function.
  6. I still very much wish we could add any number of callbacks on the timing of the animation instead of just getting an end callback.
  7. I'll take a look at this tomorrow with the monster script you have.
  8. OK, so it's something in the setup we're missing. Can you just attach the entire monster script file to this post?
  9. So first I'm curious if it's even calling the onAttacked function so comment out everything in that function and just put a System:Print() and print something to console and see if anything shows up.
  10. So that error is happening in the RaiseEvent() side of things. That first line of code you have there isn't correct though is it? local scriptFunc = events[eventName][i].scriptFunction I think that's how it looks right? (Your code as missing the part). It's hard to piece mail this stuff but you have the function Script:onAttacked() function in the crawler script too right? That's needed in that script. I would need to see the relevant parts of each script to determine exactly why it's happening.
  11. Did you subscribe to that event in the Start() function? Remember you have to always subscribe to the event as well in order to receive it.
  12. That would all depend on your game really. I don't know much about your game so it's hard for me to say. But, let's say you have enemies scattered around your level. If you wanted an enemy to be able to alert fellow enemies around them of the player when the player attacks it you could use an event for that. Your monster script would subscribe for an "onAttacked" event and inside the monster Hurt() function you could raise "onAttacked" event. All the other monsters would get that event. Now you wouldn't want ALL monsters to come charging but maybe all monsters in a radius of the monster that was attacked? In that case when you raise "onAttacked" event you can send in the parameter data that monsters position. Then in the subscribed function that you linked to the onAttacked event you can take THAT monsters location and get the distance to the passed in monsters location and if within a certain range set that monsters target to the player (I suppose that means you'd also have to pass the player (the attacker, which you have in the Hurt() function) to the onAttacked event data parameter as well so it can set the target those monsters should attack. -- I don't remember the exact function signature of Hurt but you get the idea function Script:Hurt(amount, sourceOfPain) RaiseEvent("onAttacked", { hurtMonsterPosition = self.entity:GetPosition(), player = sourceOfPain }) end -- if this is the function linked to the onAttacked event function Script:onAttacked(data) -- I don't recall if this is the correct syntax for distance checks but it gets the idea across. you'll have to research distance checks. if data.hurtMonsterPosition:Distance(self.entity:GetPosition) < 5 then -- if this monster is in a given range of the monster that was attacked then assign this monster the player target as well and it'll come running towards it! self.target = data.player end end Anytime you need to communicate between different entities is where these events can come into play. This system is one tool in your tool belt and it has a usage of inter entity communication.
  13. Rick

    Won't start

    What's your gfx card? Perhaps it's not powerful enough to run LE? Look in Documents\Leadwerks and copy/paste Leadwerks.log file here so we can see what it produced.
  14. PostRender() that's it! Yes, you want to draw your self.killMessage text in post render. That's the only way it'll show up on the screen. The context:DrawText() has to always be in PostRender() otherwise it won't show up. function Script:enemyDied(data) self.kills = self.kills + 1 WaitForSeconds(2.5); self.killMessage = "Player Killed Enemy" -- Note: if you wanted to know what kind of enemy you could have that passed into the data parameter from where you RaiseEvent (remember we passed an empty object {} but you could do something like { enemyName = "Monster" } in the RaiseEvent() and read data.enemyName here if you wanted. WaitForSeconds(1.0); while self.killMessageAlpha > 0 do self.killMessageAlpha = self.killMessageAlpha - .01 WaitForSeconds(0.25) end self.killMessage = "" -- this has to be outside the loop so the message is cleared AFTER the alpha has reached 0 self.killMessageAlpha = 1 end --draw kills context:SetBlendMode(1) context:SetColor(1,1,1,1) context:DrawText("Kills: "..self.kills,30,30,200,200) context:SetColor(Vec4(1, 1, 1, self.killMessageAlpha)) context:DrawText(self.killMessage, 30, 50, 200, 200) function Script:CleanUp() Unsubscribe(self.onDeadId) Unsubscribe(self.killMessage) -- NOTE: No need to do this. self.killMessage is just a normal string variable not an event like self.onDeadId is. You only Unsubscribe() for events end
  15. It's very easy to do with this actually. This is actually where coroutines shine! Doing things for set periods of time or over multiple frames. So assuming your UI stuff is inside your player script, you'd probably want to create a variable that will hold the text message to display on the screen. Inside Script:Start() self.killMessage = "" Since it's blank you can actually do context:DrawText() all the time in your render2D function (is that the script name? I forget). It just won't draw anything on the screen if it's blank. Then the idea is that in your enemyDead() script function you set the self.killMessage to whatever you want, then call that WaitForSeconds() and after set it back to empty string. It'll then show up on the screen when you kill someone, sit there for however many seconds you want then go away! Super easy. Now imagine you want the text to fade away instead of snap away (very polished stuff)! No problem, make another variable in Start called like self.killMessageAlpha = 1. In the render function before you draw self.killMessage set the color where the alpha value is this variable context:SetColor(Vec4(1, 1, 1, self.killMessageAlpha). Then in your enemyDead function after you've waited your seconds of displaying instead of just setting self.killMessage to empty string the idea is to make a loop where you decrease self.killMessageAlpha a little each iteration while yielding inside the loop. You could do something like: -- player around with how much you subtract and how long you wait for to get the smoothness of fading out you like while self.killMessageAlpha >= 0 do self.killMessageAlpha = self.killMessageAlpha - .01 WaitForSeconds(0.25) end -- reset the variables after we've faded out this message self.killMessage = "" self.killMessageAlpha = 1 So as you can see the idea is to create variables in your script and you can manipulate them over multiple frames easily enough inside one of these event function callbacks via coroutines. On the topic of moving it to another file, I wouldn't name it coroutines. Coroutines is just a programming language feature. Really it's an EventSystem so that's probably a better name. As far as that part in the main loop, you can add a function to your EventSytem file named something like UpdateEventSystem() and put that code in there, then call this function in Main where that code was. As far as understanding the code flow, yeah coroutines and callbacks can be confusing if you've never worked with them. Coroutines especially can be hard. So on subscription we are just storing the function callbacks with the event string name. That's it really at that point. One event string name can have many different function callbacks linked to it. When an event is raised is where things get interesting. So before we added coroutines to this all, those callback functions were just be called right there. It would just loop through all callbacks subscribed to that event string name and call them right then and there. I think that's somewhat easy to understand. You stored the functions in subscribe and call them for a given event name in raise. Each function would start at the top and go to the bottom and finish just like a normal function. We changed that when we added coroutines. Now inside raise event instead of looping through and calling the function, we loop through and get the function for the raised event string name and create a coroutine variable from it and store it in a separate table. That's all raise event does now. Then we have that loop in our main game loop that will loop over these coroutines in this other coroutine table and with coroutines you "resume" into them instead of just call them once and done. In one iteration it'll go into each function but if inside it sees a coroutine.yield() statement it'll come back out to the loop, but it remembers everything about where it left off in that function so the next game loop when we loop over that table of coroutines and resume back into them it'll pick up where they left off the last time. Once it reaches the end of any function that coroutine is marked with a status of "dead" and we'll remove it from the table of coroutines so we don't iterate over it anymore. But if that event gets raised again, it'll repeat this entire process. So in that vein you could have multiple coroutines calling that same function if you kill enemies fast enough and the last one isn't finished yet. Something to test on how it behaves. I'm a very patient person and I like teaching so keep asking those question!
×
×
  • Create New...