This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
prpl:prplsnippets [2017/12/08 13:28] – added unit movement example kajacx | prpl:prplsnippets [2025/02/14 14:57] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 6: | Line 6: | ||
If you are looking for what is possible in PRPL or some inspiration for your own units, this is a good place to start, provided you know [[prpl: | If you are looking for what is possible in PRPL or some inspiration for your own units, this is a good place to start, provided you know [[prpl: | ||
+ | |||
+ | (TODO: buildable/ | ||
===== Discovering units/ | ===== Discovering units/ | ||
Line 119: | Line 121: | ||
Self <-x <-y SetUnitPixelCoords #set pixel coordinates | Self <-x <-y SetUnitPixelCoords #set pixel coordinates | ||
endif | endif | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ===== Making a buildable & chargable unit ===== | ||
+ | |||
+ | Here is a code for making a unit that first needs to be build with lathes and then once build accepts energy from nearby energym mines (or ships with energy port). | ||
+ | |||
+ | <code prpl> | ||
+ | $MaxHealth: | ||
+ | $MaxEnergy: | ||
+ | |||
+ | once | ||
+ | #healt | ||
+ | Self < | ||
+ | Self 0 SetUnitHasHealthBar # don't display healtb bar while it has only 1 health at start | ||
+ | Self -1 SetUunitLatheDamageAmt # negative value - lathe heals the unit | ||
+ | Self 1 SetUnitLatheTargets # make lathes target this unit | ||
+ | | ||
+ | #energy | ||
+ | Self 0 SetUnitReceivesPackets # set 0 for now, so it doesn' | ||
+ | Self < | ||
+ | Self 3 SetUnitPacketDelay # accept 1 energy packet every X frames | ||
+ | Self 0 SetUnitHasEnergyBar # hide energy bar for now | ||
+ | |||
+ | #reset | ||
+ | Self 1 SetUnitHealth # start at 1 health - it would destroy itself at 0 | ||
+ | Self 0 SetUnitEnergy # reset energy to 0 | ||
+ | Self 1 SetUnitIsEnemy # make the unit enemy, so that friendly lathes will target it and heal it | ||
+ | endonce | ||
+ | |||
+ | Self GetUnitIsEnemy if | ||
+ | #while " | ||
+ | |||
+ | #display health bar only if health > 1 | ||
+ | Self GetUnitHealth 1.5 lt if | ||
+ | Self 1 SetUnitHealth # work around some wierd float calcualtion issues | ||
+ | else | ||
+ | Self 1 SetUnitHasHealthBar # show energy bar once it's being " | ||
+ | endif | ||
+ | |||
+ | #flip to gather energy when built | ||
+ | Self GetUnitHealth gte (Self GetUnitMaxHealth) if # check if at full health | ||
+ | Self 0 SetUnitIsEnemy # make unit no longer enemy, so it can receive friendly energy | ||
+ | Self 1 SetUnitReceivesPackets # receive friendly energy packets | ||
+ | Self 0 SetUnitHasHealthBar # hide health bar once it's build | ||
+ | Self 1 SetUnitHasEnergyBar # show energy bar isntead | ||
+ | Self 0 SetUnitLatheTargets # so enemies don't destroy it once built | ||
+ | endif | ||
+ | else | ||
+ | # already build | ||
+ | Self GetUnitEnergy gte (Self GetUnitMaxEnergy) if # check if at full energy | ||
+ | "Full energy!" | ||
+ | Self 0 SetUnitEnergy #reset energy back to 0 | ||
+ | endif | ||
+ | endif | ||
+ | </ | ||
+ | |||
+ | Now that's a lot of code, but the comments should explain it well enought. The only wierd bit might be hiding/ | ||
+ | |||
+ | You can go and make it do something usefull once it cahrges with energy, or you can remove the nergy reset and have it provide a pasive bonus while at full energy, the possibilites are endless. | ||
+ | |||
+ | ==== Homework ==== | ||
+ | |||
+ | Change the unit to be symetrical for both the player and the enemy - once the player captures it with lathes, the enemy can capture it as well. When in enemy control, make the unit accept enemy energy packets and up build energy as well. Finally, make the health go from 100% to 0% when being captured by the lathes, as that would more suit a flipable unit like this. | ||
+ | |||
+ | < | ||
+ | <code prpl> | ||
+ | $MaxHealth: | ||
+ | $MaxEnergy: | ||
+ | $StartAsEnemy: | ||
+ | |||
+ | once | ||
+ | #healt | ||
+ | Self < | ||
+ | Self 0 SetUnitHasHealthBar # don't display health bar on 100% health | ||
+ | Self 1 SetUunitLatheDamageAmt # positive value - lathe damages the unit | ||
+ | Self 1 SetUnitLatheTargets # always stay a valid lathe target | ||
+ | | ||
+ | #energy | ||
+ | Self 1 SetUnitReceivesPackets # always accept energy packets | ||
+ | Self < | ||
+ | Self 3 SetUnitPacketDelay #accept 1 energy packet every X frames | ||
+ | Self 1 SetUnitHasEnergyBar # always show energy bar: it will be empty when at 0 energy | ||
+ | |||
+ | #reset | ||
+ | < | ||
+ | Self Self GetUnitMaxHealth SetUnitHealth # fully heal | ||
+ | Self 0 SetUnitEnergy # start at 0 energy | ||
+ | Self < | ||
+ | @SetImageColor | ||
+ | endonce | ||
+ | |||
+ | #check health | ||
+ | Self GetUnitHealth 10 lt if # health is low enought to flip | ||
+ | # flip from enemy to player or wise versa | ||
+ | < | ||
+ | Self Self GetUnitMaxHealth SetUnitHealth # reset to full health | ||
+ | Self 0 SetUnitEnergy # reset to 0 energy | ||
+ | Self < | ||
+ | Self 0 SetUnitHasHealthBar # don't display health bar on 100% health | ||
+ | @SetImageColor | ||
+ | return # end script execution for this frame | ||
+ | endif | ||
+ | |||
+ | Self GetUnitMaxHealth sub (Self GetUnitHealth) lt (0.5) if #current health is at most 0.5 lett than max health = unit at full health | ||
+ | Self Self GetUnitMaxHealth SetUnitHealth # force set unit to full health, fixes a wierd float issue | ||
+ | else | ||
+ | Self 1 SetUnitHasHealthBar #unit has taken damage - display the health bar | ||
+ | endif | ||
+ | |||
+ | #flip to gather energy when built | ||
+ | Self GetUnitHealth gte (Self GetUnitMaxHealth) if | ||
+ | Self 0 SetUnitIsEnemy | ||
+ | Self 1 SetUnitReceivesPackets | ||
+ | Self 0 SetUnitHasHealthBar | ||
+ | Self 1 SetUnitHasEnergyBar | ||
+ | Self 0 SetUnitLatheTargets # so enemies don't destroy it once built | ||
+ | endif | ||
+ | | ||
+ | #check energy | ||
+ | Self GetUnitEnergy gte (Self GetUnitMaxEnergy) if | ||
+ | < | ||
+ | "Full energy on enemy side, hue hue." Trace #todo: actaully do something useful here | ||
+ | else | ||
+ | "Full energy on friendly side, yatta!" | ||
+ | endif | ||
+ | Self 0 SetUnitEnergy | ||
+ | endif | ||
+ | |||
+ | : | ||
+ | if (< | ||
+ | Self " | ||
+ | else | ||
+ | Self " | ||
+ | endif | ||
+ | </ | ||
+ | |||
+ | Again, most code is exaplined with comment. This time we don't show the health bar until the unit takes some damage. The "wierd float issue" was that the health would randomly decreace by a tiny amount (say, from `200` to `199.9999764`) so we fix that by forcably heling the unit when it's at full ehalth, just in case. | ||
+ | |||
+ | Aslo, when checking if the ehalth is low enought, `Self GetUnitHealth 10 lt if # health is low enought to flip` it is wise to choose a slightly larger number, like `10`, so that even when multiple lathes are targeting the unit, they will not destroy it before it can flip and fully heal itself. | ||
+ | </ | ||
+ | |||
+ | ===== Working with images ===== | ||
+ | |||
+ | Let's try a new format - we will start with a simple script of showing a star image, and then we will add new features gradually. So, here is the basics of adding an image: First, create the image you want. It must have exactly one if the following sizes: 64x64 pixels, 128x128 pixels, or 256x256 pixels. You download the 2 images used in this tutorial right here: | ||
+ | |||
+ | < | ||
+ | {{: | ||
+ | < | ||
+ | |||
+ | (It's a white image on a transparent background, so some images viewers might display it as a white square, but don't worry, it will work fine). | ||
+ | |||
+ | Next, you need to register the images into the game. In the PF map editor, go to Editor -> Map -> Custom Images -> 256x256 tab -> Select on the first slot, and then open the downlaoded file in the file chooser. | ||
+ | |||
+ | {{: | ||
+ | |||
+ | Finally, once the images are loaded into the game, you can write a PRPL script that will use the images: | ||
+ | |||
+ | <code prpl> | ||
+ | $StarFill:" | ||
+ | $StarBorder:" | ||
+ | |||
+ | once | ||
+ | Self " | ||
+ | Self " | ||
+ | Self " | ||
+ | | ||
+ | Self " | ||
+ | Self " | ||
+ | Self " | ||
+ | endonce | ||
+ | </ | ||
+ | |||
+ | Again, search for " | ||
+ | |||
+ | How it looks: | ||
+ | {{: | ||
+ | |||
+ | The interesting part here is that the image itself is whire, but the color is set in PRPL. The advantage over having the image itself colored is that we can now compute and change the color with PRPL to our liking, which we will do momentary. | ||
+ | |||
+ | But first, a few notes: | ||
+ | |||
+ | Next, let's take a look at '' | ||
+ | |||
+ | Finally, '' | ||
+ | |||
+ | ==== Making the star change color ==== | ||
+ | |||
+ | Now we are getting into some fun. Let's start by chaning the color from red to yellow by keeping the red color channel at 255 and changing the green color channel: | ||
+ | |||
+ | <code prpl> | ||
+ | $StarFill:" | ||
+ | $StarBorder:" | ||
+ | $Step:2 #the speed of color change | ||
+ | |||
+ | once | ||
+ | Self " | ||
+ | #Self " | ||
+ | Self " | ||
+ | | ||
+ | Self " | ||
+ | Self " | ||
+ | Self " | ||
+ | | ||
+ | 0 ->green | ||
+ | 1 -> | ||
+ | endonce | ||
+ | |||
+ | < | ||
+ | <-green <-Step add ->green | ||
+ | <-green 255 gt if | ||
+ | # the green color is more than the maximum value of 255 | ||
+ | 255 ->green #set it back to maximum | ||
+ | 0 -> | ||
+ | endif | ||
+ | else | ||
+ | <-green <-Step sub ->green | ||
+ | <-green 0 lt if | ||
+ | # the green color is less than the minimum value of 0 | ||
+ | 0 ->green #set it back to minimum | ||
+ | 1 -> | ||
+ | endif | ||
+ | endif | ||
+ | |||
+ | Self " | ||
+ | </ | ||
+ | |||
+ | How it looks: | ||
+ | {{: | ||
+ | |||
+ | The code should be pretty self-explanatory. If you have never worked with RGb values before and ar ewondering where the 255 number comes from, it's from the fact taht computers store color as 3 8-bit numbers, one for Red, one for Green and one for Blue (RGB). And since 8 bits can hold 256 diffent values, the color values are from the range 0-255. Finally, if you want to see some examples of colors and their RGB values, jsut any [[http:// | ||
+ | |||
+ | ==== Setting position and rotation ==== | ||
+ | |||
+ | Next we are going to make the start rotate around the core by chaning it's position, as well as rotate as an image to make it spin. Code: | ||
+ | |||
+ | <code prpl> | ||
+ | $StarFill:" | ||
+ | $StarBorder:" | ||
+ | $Step:2 #the speed of color change | ||
+ | $Distance: | ||
+ | $OrbitingSpeed: | ||
+ | $SpinningSpeed: | ||
+ | |||
+ | once | ||
+ | Self " | ||
+ | #Self " | ||
+ | Self " | ||
+ | | ||
+ | Self " | ||
+ | Self " | ||
+ | Self " | ||
+ | | ||
+ | 0 ->green | ||
+ | 1 -> | ||
+ | | ||
+ | 0 -> | ||
+ | 0 -> | ||
+ | endonce | ||
+ | |||
+ | # set the color | ||
+ | < | ||
+ | <-green <-Step add ->green | ||
+ | <-green 255 gt if | ||
+ | # the green color is more than the maximum value of 255 | ||
+ | 255 ->green #set it back to maximum | ||
+ | 0 -> | ||
+ | endif | ||
+ | else | ||
+ | <-green <-Step sub ->green | ||
+ | <-green 0 lt if | ||
+ | # the green color is less than the minimum value of 0 | ||
+ | 0 ->green #set it back to minimum | ||
+ | 1 -> | ||
+ | endif | ||
+ | endif | ||
+ | |||
+ | Self " | ||
+ | |||
+ | #set the position | ||
+ | < | ||
+ | Self " | ||
+ | Self " | ||
+ | Self " | ||
+ | Self " | ||
+ | |||
+ | #set the rotation | ||
+ | < | ||
+ | Self " | ||
+ | Self " | ||
+ | </ | ||
+ | |||
+ | Result: | ||
+ | {{: | ||
+ | |||
+ | The key to making it look good is balancing the rotations speeds properly. I definetely like it more when the start is spinning in the oposite derection than the orbit (positiv/ | ||
+ | |||
+ | ==== The homework ==== | ||
+ | |||
+ | We could go on and on, making the star bigger/ | ||
+ | |||
+ | Preview: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | Solution: | ||
+ | < | ||
+ | <code prpl> | ||
+ | $StarFill:" | ||
+ | $StarBorder:" | ||
+ | $Step:2 #the speed of color change | ||
+ | $Distance: | ||
+ | $OrbitingSpeed: | ||
+ | $SpinningSpeed: | ||
+ | $Stars:6 #the amount of stars | ||
+ | |||
+ | once | ||
+ | Self RemoveImages | ||
+ | |||
+ | <-Stars 0 do | ||
+ | Self " | ||
+ | Self " | ||
+ | | ||
+ | Self " | ||
+ | Self " | ||
+ | Self " | ||
+ | loop | ||
+ | | ||
+ | 0 ->green | ||
+ | 1 -> | ||
+ | | ||
+ | 0 -> | ||
+ | 0 -> | ||
+ | endonce | ||
+ | |||
+ | # set the color | ||
+ | < | ||
+ | <-green <-Step add ->green | ||
+ | <-green 255 gt if | ||
+ | # the green color is more than the maximum value of 255 | ||
+ | 255 ->green #set it back to maximum | ||
+ | 0 -> | ||
+ | endif | ||
+ | else | ||
+ | <-green <-Step sub ->green | ||
+ | <-green 0 lt if | ||
+ | # the green color is less than the minimum value of 0 | ||
+ | 0 ->green #set it back to minimum | ||
+ | 1 -> | ||
+ | endif | ||
+ | endif | ||
+ | |||
+ | |||
+ | < | ||
+ | < | ||
+ | |||
+ | <-Stars 0 do | ||
+ | Self " | ||
+ | |||
+ | #set the position | ||
+ | TWOPI <-Stars div I mul ->offset | ||
+ | Self " | ||
+ | Self " | ||
+ | Self " | ||
+ | Self " | ||
+ | |||
+ | #set the rotation | ||
+ | Self " | ||
+ | Self " | ||
+ | loop | ||
</ | </ | ||
</ | </ |