HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

spawn not near unit

03-19-2009, 10:09 AM#1
311
Im trying to get some random spawns in my map, but I dont want them to ever be to close to each other so is there a way to spawn units with something like

random point in region but not within 400range of any other unit
03-19-2009, 01:06 PM#2
Panto
How often are you spawning? You could make a custom region on the fly that it is the entire spawn area minus regions defined by proximity to existing units.

Maybe, in theory anyway.

Moving you to the triggering forum.
03-19-2009, 01:36 PM#3
Vexorian
Quote:
random point in region but not within 400range of any other unit

If it is just a single unit then you can do something like

Collapse JASS:
loop
     set x = pickRandomX()
     set y = pickRandomX()
     exitwhen  {unit is not in range of x,y}
endloop
you can even prove it is uniform on the set of valid points.

For more units you can do:

Collapse JASS:
loop
     set x = pickRandomX()
     set y = pickRandomX()
     set i=0
     good = true
     loop
            exitwhen (i== N) or not good
            if { unit[i] is in range of x,y } then
                   good=false
            endif
            set i=i+1
     endloop
     exitwhen  (good)
endloop

However, always make sure there are at least as much valid points than invalid points, else this code will take a while... (The expected number of tries is (P+1)/P where P is the probability to find a valid point. With P>=0.5 , that's a breeze.

Also, if there are a lot of units, like 50, it might be too slow for a periodic event. Let me think for a while on how to solve it later...
03-19-2009, 08:10 PM#4
311
anyway to do it in gui? I dont know JASS
It happens basicly at the start of a game or every few zones. Basicly when the map starts im creating a bunch of random units all over the map in my rpg. Right now however sometimes to many units get clusted then one part of the map looks empty so Im just trying to get stuff more spread out but still random
03-19-2009, 08:49 PM#5
Vexorian
It isn't really Jass, it is pseudocode.

More spread out? You could divide the map in n section and make sure to create one random unit per section.
03-20-2009, 01:25 AM#6
cosmicat
Pseudo-GUI:
Collapse Events
Event - Periodic Event every x seconds (or whatever)
Collapse Conditions
(none)
Collapse Actions
Collapse Pick every player in (player group) and do actions:
Create 1 (unit) for (player) at (random location) facing (angle)
Collapse Pick every unit in (x range of (last created unit)) matching (matching unit is of type (unit-type)) and do actions:
Kill (last created unit)
Remove (last created unit) from the game
Add (this trigger) to queue, ignoring conditions
Exit this loop (I forget the GUI function that does exitwhen(true))
Dreadfully inefficient compared to the methods described above, but I think it achieves the most authentic effect. Killing and removing the unit happens instantaneously, so it won't show up on the map at all; for all intents and purposes, it wasn't there. The "Pick every unit" function only does anything if there's at least one unit of the type described in range, so it shouldn't kill every unit that's created. If there's hiccups, let me know...
03-20-2009, 03:12 AM#7
Vexorian
That's actually pretty awful.

Is there an actual reason to trust it on a trigger running periodically rather than just call the trigger after creating the unit? There isn't a lot of sense in actually doing this after the unit was created...You could just prevent creating it whatseover..
03-20-2009, 03:20 AM#8
cosmicat
Good point. The player group thing is unnecessary, too, since he's probably just doing this for the "Neutral Hostile" player. Revised:
Pseudo-GUI:
Collapse Events
(none - call the trigger a certain number of times on map initialization or something)
Collapse Conditions
(none)
Collapse Actions
set newUnitPos = random location in (Playable Map Area)
Collapse Pick every unit in (400 range of (newUnitPos)) matching (matching unit is of type (unit-type)) and do actions:
Add (this trigger) to queue, ignoring conditions
Skip remaining actions
Create 1 (unit-type) for (Neutral Hostile) facing default building facing degrees
Thanks for the brutally honest feedback. Guess I need to get better at GUI efficiency, too, not just JASS (been trying to set aside time to understand inlining, but...ugh, guess I'm just stupid or something).
03-24-2009, 10:57 AM#9
311
Trigger:
Untitled Trigger 002
Collapse Events
Unit - A unit Dies
Collapse Conditions
(Owner of (Dying unit)) Equal to Player 6 (Orange)
Collapse Actions
Wait 60.00 game-time seconds
Unit - Create 1 (Unit-type of (Dying unit)) for Player 6 (Orange) at (Random point in (Region centered at (Position of (Dying unit)) with size (500.00, 500.00))) facing Default building facing degrees

Trigger:
zone 1
Collapse Events
Map initialization
Conditions
Collapse Actions
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees
Unit - Create (Random integer number between 0 and 1) Zombie act 1 for Player 6 (Orange) at (Random point in act 1 1st part <gen>) facing Default building facing degrees

k those are my 2 triggers one is to set up spawns at the start of game, and one is for respawn after they die. I was always told not to use wait trigger, but it seems to work fine so far so im not sure. Anyway how would I convert that to making units not spawn to close together?
03-25-2009, 05:37 AM#10
cosmicat
CreateLoneUnit:
CreateLoneUnit
Events
Conditions
Collapse Actions
Set spawn = True
Set spawnPoint = (Random point in spawnRegion)
Collapse Unit Group - Pick every unit in (Units within 400.00 of spawnPoint matching ((Owner of (Matching unit)) Equal to Player 6 (Orange))) and do (Actions)
Collapse Loop - Actions
Set spawn = False
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
spawn Equal to True
Collapse Then - Actions
Unit - Create 1 spawnUnit for Player 6 (Orange) at spawnPoint facing Default building facing degrees
Else - Actions

StartingCreeps:
StartingCreeps
Collapse Events
Map initialization
Conditions
Collapse Actions
Collapse For each (Integer A) from 1 to 11, do (Actions)
Collapse Loop - Actions
Set spawnRegion = act 1 1st part <gen>
Set spawnUnit = Zombie act 1
Trigger - Run CreateLoneUnit <gen> (ignoring conditions)

And here's where waits become a problem. Since you're using GUI, not JASS, you can't use more than one local variable - and here you need two. I can write you a global JASS function, but then you'd have to call it with a custom script. I lack the skill and knowledge to make a self-contained trigger that does all the things you'd want. If you're comfortable with that...

Okay, here's the JASS script. Copy and paste it into your "global functions" section (the "trigger" in the Trigger Editor that has the same name as the map).
Collapse JASS:
globals
    constant real DISTANCE = 400.00
        // Minimum distance between two spawned creeps
    constant player ENEMY  = Player(5)
        // Enemy player.  Player(5) is actually Player 6 (orange).
endglobals

// Do not change anything below this comment or ELSE.

function StupidBoolExprFy takes nothing returns boolean
    return IsUnitOwnedByPlayer(GetFilterUnit(),ENEMY)
endfunction

function CreateLoneUnit takes rect spawnRegion, integer spawnUnit returns nothing
    local real xPos = GetRandomReal(GetRectMinX(spawnRegion),GetRectMaxX(spawnRegion))
    local real yPos = GetRandomReal(GetRectMinY(spawnRegion),GetRectMaxY(spawnRegion))
    local group otherUnits = null
    call GroupEnumUnitsInRange(otherUnits,xPos,yPos,DISTANCE,Filter(function StupidBoolExprFy))
    if otherUnits == null then
        call CreateUnit(ENEMY,spawnUnit,xPos,yPos,bj_UNIT_FACING)
    else
        call CreateLoneUnit(spawnRegion, spawnUnit)
    endif
    call DestroyGroup(otherUnits)
    return
endfunction

function CreateLoneUnitWait takes rect spawnRegion, integer spawnUnit, real duration returns nothing
    if duration > 0 then
        call PolledWait(duration)
    endif
    call CreateLoneUnit(spawnRegion, spawnUnit)
    return
endfunction
To use it, you would use a custom script. For example, the two GUI triggers you have above would look like this now:
ReplaceCreeps:
ReplaceCreeps
Collapse Events
Unit - A unit Dies
Collapse Conditions
(Owner of (Dying unit)) Equal to Player 6 (Orange)
Collapse Actions
Set spawnRegion = (Region centered at (Position of (Dying unit)) with size (500.00, 500.00))
Set spawnUnit = (Unit-type of (Dying unit))
Custom script: call CreateLoneUnitWait(udg_spawnRegion, udg_spawnUnit, 60.00)
StartingCreeps:
StartingCreeps
Collapse Events
Map initialization
Conditions
Collapse Actions
Collapse For each (Integer A) from 1 to 11, do (Actions)
Collapse Loop - Actions
Set spawnRegion = act 1 1st part <gen>
Set spawnUnit = Zombie
Custom script: call CreateLoneUnit(udg_spawnRegion, udg_spawnUnit)

(((waits for Vexorian [or worse, *not* Vexorian] to pick this apart)))